Skip to content

Debug Dump (`/debug-dump`)

/debug-dump is a slash command available inside interactive chat and code sessions. I hit a bug in a gth chat or gth code session and want to attach a debug dump to the issue I’m about to file. Here’s how:

  1. Reproduce the bug in the session (or get as close to it as you can — the dump captures everything so far, not what happens after).

  2. Type /debug-dump and press enter:

    /debug-dump
  3. Gaunt Sloth redacts secrets, writes the archive, and prints its path:

    Debug dump written — secrets redacted
    Archive: /Users/you/.gsloth/debug-dumps/2026-07-18T22-24-37-118Z
    Secrets were redacted (API keys, tokens and auth headers replaced with <redacted>).
    Redaction is best-effort and pattern-based — review before sharing.
    To write a raw, unredacted archive: set `debugDump.redact: false` in your gsloth config,
    or run `/debug-dump --unsafe-no-redact`.

    Redaction is on by default (see Redaction). It masks known secret shapes and values — it does not sanitize general file contents or transcript text the session captured — so still review the archive before you attach it to a public issue.

  4. Attach the reviewed file(s) — or the whole reviewed directory — to your GitHub issue (see CONTRIBUTING.md for the issue/PR process).

Each run creates one new, timestamped directory under the global ~/.gsloth/debug-dumps/ (not the project’s .gsloth/), so successive dumps never collide or overwrite each other:

~/.gsloth/debug-dumps/<timestamp>/
File Contents
transcript.json The full session transcript so far — every turn, tool call, and tool result.
config.json The resolved effective configuration (the live GthConfig) for the session.
model-request.json What shaped the last model call besides the messages: the composed system prompt, the tool definitions with their schemas, the model params, and the tool choice. Omitted before the first model call.
model-messages.json The exact messages sent to the model on that last call, after summarization and middleware — what the model actually saw, which is not the same array as transcript.json. Omitted before the first model call.
approvals.json One entry per gated tool call: which stage of the approvals gate decided it (a deny entry, the deterministic floor, an allow entry, the auto-rater), what the rater was sent and what it answered, and what became of the call — approvals included. Omitted when the session gated nothing. See What approvals.json answers.
env.json gthVersion, nodeVersion, platform, and the model display name.
debug-log.txt The in-memory debug-log ring buffer for this session.
git-state.json branch, remote, and dirty — only written when the session’s working directory is inside a git repository; omitted entirely otherwise.

Values that aren’t directly JSON-safe (functions, bigints, circular references — e.g. the live LLM client object embedded in the resolved config) are stringified or broken rather than causing the dump to fail partway through; source: packages/core/src/utils/debugDump.ts, verified by packages/core/spec/debugDump.spec.ts.

If you are filing a bug about a command that was blocked — or one that ran when you did not expect it to — this is the file to read. Each entry covers one gated tool call:

  • Which layer stopped (or allowed) it. stage names it: deny-list, hardline-floor, escalate-entry, allow-list, allow-tripwire, rater, bypass or not-gated. “Blocked” and “escalated” cover several different mechanisms, and they need different fixes — a deny entry you wrote is edited in your config, whereas a rater verdict is a model’s judgement.
  • What the rater was shown. rating.prompt holds the exact system and user strings that were sent, captured as they were sent rather than rebuilt afterwards.
  • What it answered. rating.rawResponse is the model’s untouched reply and rating.verdict is the outcome and reason it was read as. Both are recorded whether the call was approved or refused.
  • Whether your own messages were in view. rating.negotiation.userMessagesPopulated — with a sentence in userMessagesNote saying what an empty window means for that round. The first round of a negotiation deliberately sees the command alone, so an empty window there is expected, not a fault.
  • Where the exchange stood. budget reports the rejections so far against the two limits that end an argument at a human.

Redaction (below) applies to this file exactly as it does to the transcript.

/debug-dump runs a secret-redaction pass over every file above before it is written. It is on by default — the config toggle is debugDump.redact (see Configuration → Debug Dump Redaction).

What it removes. Each match is replaced with the literal marker <redacted>:

  • The values of secret-named environment variables (*_API_KEY, *_TOKEN, *_SECRET, *_KEY, anything containing PASSWORD) and inline config secrets — substituted wherever they appear, across every file in the archive.
  • Well-known provider key shapes: OpenAI / Anthropic (sk-…, sk-ant-…), Google (AIza…), xAI (xai-…), Groq (gsk_…), and GitHub tokens (classic ghp_/gho_/… and fine-grained github_pat_…).
  • Authorization and Bearer header values (any scheme, including non-standard ones and AWS SigV4 Credential= / Signature=), and credentials embedded in a URL (scheme://user:pass@host — the user:pass is masked, the host kept).
  • In config.json: the value of any secret-named field (apiKey, token, secret, …) is masked while the key is kept, and the live model object is reduced to a { type, model } descriptor so its internals never reach disk.

What it does not do. Redaction is best-effort and pattern-based — it targets known secret shapes and values, not arbitrary sensitive data. It does not scrub general file contents, source code, or prose the transcript captured, and it deliberately does not redact high-entropy strings (to avoid gutting the dump with false positives). It is a safety net, not a guarantee: review a dump before you share it.

Opting out. To write a raw, unredacted archive, either set it persistently in config:

{
"debugDump": {
"redact": false
}
}

or opt out for a single dump by passing the flag when you type the command in a session:

/debug-dump --unsafe-no-redact

With redaction off, the archive is written as-is and the command prints a loud “UNSANITIZED — may contain secrets” warning in place of the redacted-by-default notice.

/debug-dump is one entry in the shared slash-command registry (packages/agent/src/modules/slashCommands.ts, re-exported for the TUI as packages/app/src/tui/slashCommands.ts), and both interactive surfaces wire an archive writer to it. Tracing where each renders:

  • gth chat and gth code (packages/app/src/commands/chatCommand.ts / codeCommand.ts) both call startSession() (packages/app/src/modules/startSession.ts), which mounts the Ink TUI when the environment favors it (shouldUseTui(), packages/app/src/tui/shouldUseTui.ts): both stdin and stdout must be a real TTY, TERM must not be dumb, --no-tui/GTH_NO_TUI must not be set, and — unless --tui is passed explicitly — CI must not be set.
  • Outside those conditions, chat/code fall back to the plain readline session (packages/agent/src/modules/interactiveSessionModule.ts). It shares the same slash-command registry and forwards to the same writer, so /debug-dump writes a real archive there too. That session keeps no on-screen transcript, so transcript.json is thinner than the TUI’s; every other file is the same.
  • ask, exec, review, and pr run one-shot through runSingleShot() / review() (packages/app/src/commands/askCommand.ts, execCommand.ts, reviewCommand.ts, prCommand.ts) — there is no rendered session and no slash-command dispatch at all, so there is nowhere to type /debug-dump into.

So: /debug-dump is available in interactive gth chat / gth code sessions — the Ink TUI and the readline fallback alike. It is not available in ask, exec, review or pr.

If a dumpDebugSession writer isn’t wired into the session at all (only happens in the fixture/demo agent used for internal testing, never a real chat/code run), the command reports itself unavailable instead of writing anything:

Debug dump unavailable
No debug-dump writer is available in this session.
This is only available in a real session (not the fixture/demo agent).

Writing the archive never aborts your session:

  • Not inside a git repository (or git isn’t installed) → git-state.json is simply omitted.
  • Installed version can’t be determined → env.json reports "unknown" for gthVersion.
  • Non-JSON-safe or circular data in the transcript/config → handled per “What’s in the archive” above, rather than throwing.
  • Secrets are redacted by default; opt out per Redaction above. There is no option to change the output location. Because the archive lives under your home directory, it is never covered by a project’s .gitignore.
  • Old archives are not cleaned up automatically; clear out ~/.gsloth/debug-dumps/ yourself once you no longer need old dumps.