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
{{ message }}
This repository was archived by the owner on Aug 27, 2026. It is now read-only.
gsd-tools supports a JSON error mode that emits all errors as structured
JSON objects on stderr instead of free-form text. This is the recommended
surface for tests and tooling that need to assert on error types without
grepping raw text (see CONTRIBUTING.md — "Prohibited: Raw Text Matching on
Test Outputs").
Activating
Either flag or env var activates the mode:
# Flag (preferred in test code):
node gsd-tools.cjs --json-errors <command> [args]
# Env var (preferred for shell wrappers and CI):
GSD_JSON_ERRORS=1 node gsd-tools.cjs <command> [args]
Wire format
On any error, exactly one JSON line is written to stderr and the process
exits with code 1:
config-get for a key that is absent from the config file
config_no_file
Config operation when .planning/config.json does not exist
config_parse_failed
Config file exists but is not valid JSON
config_invalid_key
config-set for a key outside the allowed whitelist
Phase / workflow errors
Code
When emitted
phase_not_found
Phase directory lookup returns no match
summary_no_planning
Summary operation when no .planning/ directory exists
Graphify errors
Code
When emitted
graphify_no_graph
Graphify query or diff when no graph has been built
graphify_invalid_query
Graphify query with a malformed query string
Hook / security errors
Code
When emitted
hooks_opt_out
Hooks are disabled via opt-out config
security_scan_failed
Security scan produced a finding that blocks the operation
Fallback
Code
When emitted
unknown
All other errors without a specific reason code assigned
Writing tests
Always parse stderr with JSON.parse and assert on typed fields. Never use
.includes(), .match(), or regex on the raw error string.
// CORRECT: parse then assert on typed fieldconstresult=runGsdTools(['--json-errors','bogus-command'],tmpDir);assert.strictEqual(result.success,false);consterr=JSON.parse(result.error);assert.strictEqual(err.ok,false);assert.strictEqual(err.reason,'sdk_unknown_command');// WRONG: text matching (banned by lint-no-source-grep policy)// assert.ok(result.error.includes('Unknown command'));
Adding a new error code
Add the constant to ERROR_REASON in
gsd-core/bin/lib/core.cjs (snake_case, prefixed by subsystem).
Pass it as the second argument to error() at the call site.
Add a row to this document.
Add a test asserting the new reason code via JSON.parse.