garrytan/gstack · error · Error

Unknown explain level: ${val}. Use 'default' or 'terse'.

Error message

Unknown explain level: ${val}. Use 'default' or 'terse'.

What it means

The EXPLAIN_LEVEL IIFE in scripts/gen-skill-docs.ts:143 accepts only 'default' (sections render unconditionally; the model skips them when EXPLAIN_LEVEL: terse appears in the preamble echo) or 'terse' (compresses preamble prose at gen time). Other values throw.

Source

Thrown at scripts/gen-skill-docs.ts:143

    throw new Error(`Unknown catalog mode: ${val}. Use 'trim' (default) or 'full'.`);
  }
  return val;
})();

// ─── Explain-level Overlay ──────────────────────────────────
// --explain-level=terse compresses preamble prose (writing-style, completeness,
// confusion-protocol, context-health) to a single pointer line at gen time.
// Default keeps the runtime-conditional behavior (sections render unconditionally,
// the model skips them when EXPLAIN_LEVEL: terse appears in the preamble echo).
// Opt-in via the build flag so most users get the runtime-flexible default.
const EXPLAIN_LEVEL_ARG = process.argv.find(a => a.startsWith('--explain-level'));
const EXPLAIN_LEVEL: 'default' | 'terse' = (() => {
  if (!EXPLAIN_LEVEL_ARG) return 'default';
  const val = EXPLAIN_LEVEL_ARG.includes('=')
    ? EXPLAIN_LEVEL_ARG.split('=')[1]
    : process.argv[process.argv.indexOf(EXPLAIN_LEVEL_ARG) + 1];
  if (val !== 'default' && val !== 'terse') {
    throw new Error(`Unknown explain level: ${val}. Use 'default' or 'terse'.`);
  }
  return val;
})();

// ─── Out-dir (dev workspace render isolation) ───────────────
// --out-dir <abs-dir> redirects Claude SKILL.md + section output to a separate
// (untracked) directory instead of writing in place, AND rewrites the literal
// section-base path (`~/.claude/skills/gstack/<skill>/sections/`) inside the
// generated content to point at the out-dir, so section Reads resolve to the
// rendered copy rather than the global install. Used by bin/dev-setup to render
// the gbrain `:user` variant for a Conductor workspace without dirtying tracked
// source. Default (unset) = in-place, behavior unchanged. Claude host only.
const OUT_DIR_ARG = process.argv.find(a => a.startsWith('--out-dir'));
const OUT_DIR: string | null = (() => {
  if (!OUT_DIR_ARG) return null;
  const val = OUT_DIR_ARG.includes('=')
    ? OUT_DIR_ARG.split('=')[1]
    : process.argv[process.argv.indexOf(OUT_DIR_ARG) + 1];

View on GitHub (pinned to 94993f7401)

Solutions

  1. Omit the flag to keep the runtime-flexible default
  2. Pass exactly `--explain-level=terse` to compress preamble prose at gen time
  3. Use `--explain-level=default` to be explicit

Example fix

// before
bun run gen:skill-docs -- --explain-level=quiet
// after
bun run gen:skill-docs -- --explain-level=terse
Defensive patterns

Strategy: type-guard

Validate before calling

const VALID = new Set(['default', 'terse']);
const arg = process.argv.find(a => a.startsWith('--explain-level'));
const val = arg?.includes('=') ? arg.split('=')[1] : process.argv[process.argv.indexOf(arg!) + 1];
if (val != null && !VALID.has(val)) {
  console.error('--explain-level must be one of: default, terse');
  process.exit(2);
}

Type guard

const isExplainLevel = (v: string): v is 'default' | 'terse' => v === 'default' || v === 'terse';

Prevention

When it happens

Trigger: Passing `--explain-level=verbose`, `--explain-level=quiet`, or `--explain-level terse2`. Confusing this with a numeric verbosity scale.

Common situations: Trying familiar verbosity words (quiet/verbose) that aren't supported. Copying a flag from another tool.

Related errors


AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12). Data as JSON: /api/errors/563b8b607c1a7826. Report an issue: GitHub.