The Path Bug That Mirrored Your Filesystem

· SysMARA Team

A user ran the SysMARA one-prompt workflow: npm install @sysmara/core && npx sysmara init, wrote their YAML specs, ran npx sysmara build. The CLI reported success — 45 files generated across 15 capabilities. But when they opened app/generated/, instead of finding routes/, tests/, and metadata/, they found a recreation of their filesystem starting from the root: Users/.../app/generated/routes/...

The entire absolute path had been nested inside the generated directory.

The Root Cause: Double Path-Join

The bug lived at the intersection of two correct-looking pieces of code.

The capability compiler accepted an outputDir parameter and used it to construct file paths:

// In capability-compiler.ts
const routePath = outputDir + "/routes/" + capability.name + ".ts";
// outputDir = "/abs/path/app/generated"
// routePath = "/abs/path/app/generated/routes/create_user.ts"

The CLI command that called the compiler then joined these paths with the output directory again:

// In build.ts
const filePath = path.join(generatedDir, file.path);
// generatedDir = "/abs/path/app/generated"
// file.path    = "/abs/path/app/generated/routes/create_user.ts"
// Result: "/abs/path/app/generated/abs/path/app/generated/routes/..."

Node's path.join() does not treat an absolute second argument specially the way path.resolve() does. It strips the leading slash and concatenates. The result is a valid (but deeply nested) path that fs.mkdir({ recursive: true }) happily creates.

Why It Passed Tests

The compiler's unit tests verified that the returned paths contained the outputDir prefix:

expect(paths).toContain(outputDir + "/routes/create-user.ts");

This assertion passed because the compiler did include the prefix. The test never checked what happened when a consumer later joined that path with the same directory. The integration tests used in-memory checks and didn't write files to disk, so the double-nesting never materialized.

The Fix

The fix was straightforward: make the compiler return relative paths.

// Before (bug):
const routePath = outputDir + "/routes/" + capability.name + ".ts";

// After (fix):
const routePath = "routes/" + capability.name + ".ts";

The outputDir parameter was removed entirely from compileCapabilities(). The CLI commands already know the output directory — the compiler does not need to.

The Lesson

Path construction bugs are insidious because they often produce valid filesystem operations. The directory gets created, the file gets written, and the process exits cleanly. The only signal that something is wrong is the unexpected directory structure.

When a function returns a path, the contract must be explicit: is it absolute or relative? Who owns the base directory? In SysMARA's case, the compiler was producing a value that looked like an absolute path but was consumed as a relative one. The fix was to make the contract match the usage: the compiler returns relative paths, and the caller joins them with the output directory exactly once.

If you were affected by this bug, upgrade to @sysmara/core@0.5.1 and re-run sysmara build. You can safely delete the spurious nested directories inside app/generated/.