Summary
The src/ audit found 14 issues across 104 files: 3 high-severity blocking operations in async contexts, 9 medium-severity sync FS calls in async call chains, and 20+ silent catch blocks violating AGENTS.md §1.1.
Environment
- OS: Linux 7.0.14-5-pve
- Node.js: v25.8.1
- madz version: 1.38.15
- LLM provider: Unknown — user to confirm
Reproduction
Run the audit tool or manually grep for sync FS calls in async contexts:
- Check
src/memory/context.js — loadContext() uses readFileSync/readdirSync
- Check
src/memory/prompts.js — loadSystemPrompt() uses readFileSync
- Check
src/skills/registry.js — getSkillBody() uses readFileSync
- Verify these are called from async contexts (scheduler, deepAgents, TUI)
Expected Behavior
- No blocking operations in async functions (per AGENTS.md §1.1)
- All catch blocks should log or re-throw errors (per AGENTS.md §1.1)
Actual Behavior
- 3 high-severity files use sync FS in async call chains
- 9 medium-severity files use sync FS in async call chains
- 20+ silent catch blocks across the codebase
Additional Context
Full audit details:
High Severity — Blocking Operations in Async Contexts
| File |
Line |
Issue |
src/memory/context.js |
1-95 |
readFileSync/readdirSync in loadContext() — called from async src/scheduler/scheduler.js:198 and async src/agent/deepAgents.js:126 (via loadSystemPrompt) |
src/memory/prompts.js |
1-33 |
readFileSync in loadSystemPrompt() — called from async src/agent/deepAgents.js:126, async src/scheduler/scheduler.js:198, and async src/tui/app.js:368,488 |
src/skills/registry.js |
154-163 |
readFileSync in getSkillBody() — called from async src/tools/skills.js:80 (skillViewImpl) |
Medium Severity — Sync FS in Files Called from Async Contexts
| File |
Lines |
Issue |
src/memory/reader.js |
52 |
readFileSync in readMemoryFile() — called from async src/tools/session_search.js:78,83,204 |
src/memory/writer.js |
30,57 |
mkdirSync/writeFileSync in writeMemoryFile() — called from async src/tools/sampling.js:64 (via writeFile), async src/tools/skills.js:268 |
src/session/loader.js |
1-77 |
readFileSync/readdirSync/statSync in loadSession() — called from async src/session/factory.js |
src/memory/profile.js |
67,92 |
readFileSync/writeFileSync/mkdirSync in loadProfile()/saveProfile() — called from async src/session/onboarding.js:192 |
src/sandbox/runner.js |
43,46 |
existsSync/readFileSync in detectShebang() — called from async sandbox execution path |
src/skills/discoverer.js |
1-219 |
readFileSync/readdirSync/statSync/existsSync in discoverSkills() — called from async src/skills/registry.js:37 (discover()) |
src/memory/retention.js |
1-68 |
readFileSync/readdirSync/statSync/unlinkSync in cleanRetainedMemory()/enforceMaxEntries() — check callers for async usage |
src/config/loader.js |
147,169 |
readFileSync/writeFileSync in loadConfig()/setConfigValue() — module-level init + sync function, imported by async files |
Medium Severity — Silent Catch Blocks (AGENTS.md §1.1)
AGENTS.md §1.1 prohibits catch (err) {} empty or silent catch blocks. The following use bare catch {} with no logging:
| File |
Line |
Pattern |
src/memory/retention.js |
29,63 |
catch {} — silently skips directory errors in retention cleanup |
src/memory/expireEphemeral.js |
23,52,64 |
catch {} — silently skips read errors, directory errors, and deletion errors |
src/scheduler/scheduler.js |
65,69,197,200 |
catch {} — silently skips schedule load, run, and context load failures |
src/scheduler/cron.js |
429,432,439,475,479 |
catch {} — silently skips readdir, mkdir, readFile, and job read failures |
src/skills/discoverer.js |
42,57,81,94,172 |
catch {} — silently skips YAML parse, stat, and directory errors |
src/agent/agents/*.js |
17 (×9 files) |
catch {} — silently returns "" when prompt files are missing (coding, debug, documentation, code-review, search, security-audit, performance, testing, research) |
src/tui/contextTokens.js |
21,40 |
catch {} — silently returns 0 on token calculation errors |
src/tui/statusBar.js |
35 |
catch {} — silently hides status bar errors |
src/workspace/loadAgents.js |
16 |
catch {} — silently skips AGENTS.md load failures |
Low Severity — Minor
| File |
Line |
Issue |
src/logger.js |
27 |
readFileSync for Alpine detection — acceptable (module-level init, not async) |
src/logger.js |
135 |
TODO comment about pino.multistream deprecation — noted, not actionable now |
Summary
- 10 files use synchronous
fs operations (readFileSync, writeFileSync, readdirSync, statSync, existsSync, mkdirSync, unlinkSync)
- 7 of those are called from async contexts (directly or transitively)
- 20+ silent catch blocks across the codebase violate AGENTS.md §1.1
- No hardcoded secrets, eval(), SQL injection vectors, or wildcard exports found
- No console.log() in production code
Summary
The src/ audit found 14 issues across 104 files: 3 high-severity blocking operations in async contexts, 9 medium-severity sync FS calls in async call chains, and 20+ silent catch blocks violating AGENTS.md §1.1.
Environment
Reproduction
Run the audit tool or manually grep for sync FS calls in async contexts:
src/memory/context.js—loadContext()usesreadFileSync/readdirSyncsrc/memory/prompts.js—loadSystemPrompt()usesreadFileSyncsrc/skills/registry.js—getSkillBody()usesreadFileSyncExpected Behavior
Actual Behavior
Additional Context
Full audit details:
High Severity — Blocking Operations in Async Contexts
src/memory/context.jsreadFileSync/readdirSyncinloadContext()— called from asyncsrc/scheduler/scheduler.js:198and asyncsrc/agent/deepAgents.js:126(vialoadSystemPrompt)src/memory/prompts.jsreadFileSyncinloadSystemPrompt()— called from asyncsrc/agent/deepAgents.js:126, asyncsrc/scheduler/scheduler.js:198, and asyncsrc/tui/app.js:368,488src/skills/registry.jsreadFileSyncingetSkillBody()— called from asyncsrc/tools/skills.js:80(skillViewImpl)Medium Severity — Sync FS in Files Called from Async Contexts
src/memory/reader.jsreadFileSyncinreadMemoryFile()— called from asyncsrc/tools/session_search.js:78,83,204src/memory/writer.jsmkdirSync/writeFileSyncinwriteMemoryFile()— called from asyncsrc/tools/sampling.js:64(viawriteFile), asyncsrc/tools/skills.js:268src/session/loader.jsreadFileSync/readdirSync/statSyncinloadSession()— called from asyncsrc/session/factory.jssrc/memory/profile.jsreadFileSync/writeFileSync/mkdirSyncinloadProfile()/saveProfile()— called from asyncsrc/session/onboarding.js:192src/sandbox/runner.jsexistsSync/readFileSyncindetectShebang()— called from async sandbox execution pathsrc/skills/discoverer.jsreadFileSync/readdirSync/statSync/existsSyncindiscoverSkills()— called from asyncsrc/skills/registry.js:37(discover())src/memory/retention.jsreadFileSync/readdirSync/statSync/unlinkSyncincleanRetainedMemory()/enforceMaxEntries()— check callers for async usagesrc/config/loader.jsreadFileSync/writeFileSyncinloadConfig()/setConfigValue()— module-level init + sync function, imported by async filesMedium Severity — Silent Catch Blocks (AGENTS.md §1.1)
AGENTS.md §1.1 prohibits
catch (err) {}empty or silent catch blocks. The following use barecatch {}with no logging:src/memory/retention.jscatch {}— silently skips directory errors in retention cleanupsrc/memory/expireEphemeral.jscatch {}— silently skips read errors, directory errors, and deletion errorssrc/scheduler/scheduler.jscatch {}— silently skips schedule load, run, and context load failuressrc/scheduler/cron.jscatch {}— silently skips readdir, mkdir, readFile, and job read failuressrc/skills/discoverer.jscatch {}— silently skips YAML parse, stat, and directory errorssrc/agent/agents/*.jscatch {}— silently returns "" when prompt files are missing (coding, debug, documentation, code-review, search, security-audit, performance, testing, research)src/tui/contextTokens.jscatch {}— silently returns 0 on token calculation errorssrc/tui/statusBar.jscatch {}— silently hides status bar errorssrc/workspace/loadAgents.jscatch {}— silently skips AGENTS.md load failuresLow Severity — Minor
src/logger.jsreadFileSyncfor Alpine detection — acceptable (module-level init, not async)src/logger.jsSummary
fsoperations (readFileSync,writeFileSync,readdirSync,statSync,existsSync,mkdirSync,unlinkSync)