> ## Documentation Index
> Fetch the complete documentation index at: https://docs.basemode.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Debugging injection

> Nothing arrived and you expected it to. What controls injection, how to preview it before you send a prompt, how to run a hook by hand, and where the audit trail is.

Start here: **silence is the normal state.** base suppresses output that has not changed, so a session that says nothing at the start is usually a session where nothing needed saying. Before debugging, decide whether something is actually wrong.

## Preview instead of guessing

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
base context "we need to refund the invoice"
base context --list
```

**Why it works.** `base context` runs the same matching engine the hooks run, against text you supply, and prints what would have been injected. It is read-only and does not touch session state.

This answers most questions in one step. If `base context` returns nothing for the text you actually sent, the problem is upstream of the hooks entirely.

## The four things that control injection

| Layer            | What it decides                        | Context-aware?                                        |
| ---------------- | -------------------------------------- | ----------------------------------------------------- |
| Domain matching  | *What* is eligible                     | No. Plain substring and path matching.                |
| Suppression      | Whether you have seen it already       | No. Output is hashed and unchanged output is skipped. |
| Character budget | How much fits                          | No. `signal.max_chars`, default 2000.                 |
| Brackets         | How much and how often rules re-inject | Yes, in percent mode.                                 |

The first three are purely about triggers and content. Only the bracket layer looks at how full your context window is.

## Brackets, and why the same rules keep appearing

Brackets stage injection by how deep you are into a session: FRESH, MODERATE, DEPLETED, CRITICAL. In percent mode, base reads real depletion from the live transcript and compares it against `bracket.context_window` (default 200000), with thresholds at 20, 45 and 70 percent.

**Why it works.** Bracket rules are deliberately never deduplicated. They re-inject every prompt, on purpose, so the standing rules you care most about do not quietly erode as a conversation fills up. If you are seeing the same rules every turn, that is the feature.

**The gotcha.** `bracket.mode` absent means turns, not percent. That is deliberate: defaulting an absent key to percent would measure every older install against a 200k window, and anyone on a larger-context model would compute several times their real depletion and pin to CRITICAL permanently. New installs write the key explicitly. Verified from source at `4866996`, the commit the shipped 0.13.2 binary was built from.

## The one that catches everyone

<Warning>
  A matched `*star command` short-circuits domain matching for that prompt. Your rules do not arrive that turn, and nothing tells you.

  Rule out this cause first. It is the most common one by a distance.
</Warning>

## Turn on the diagnostics

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
base config set devmode.enabled true
```

Hook output then carries a block naming which domains matched, why, and what was deduplicated or suppressed. Turn it off when you are done tuning.

## Run the hook by hand

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
echo '{"prompt":"we need to refund the invoice"}' | base hook user-prompt-submit
echo '{}' | base hook session-start
```

**Why it works.** This bypasses your agent entirely and puts the hook's own stdout and stderr in front of you. There are five events: `session-start`, `user-prompt-submit`, `pre-tool-use`, `post-tool-use` and `stop`.

**The gotcha.** Read stderr. It is the only place errors go.

## Why errors are invisible

<Warning>
  **Hooks fail open.** Every error is caught, written to stderr, and the process exits 0 with empty stdout. A broken hook is indistinguishable from a hook that had nothing to say.
</Warning>

This is deliberate and it is the right trade: a corrupt graph or a failed extraction should never stop you working. The cost is that silent breakage can persist unnoticed, because your agent will usually not show you hook stderr.

So do not infer failure from missing output. Run the hook by hand, or read the log.

## The audit trail

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
tail -f .base/hook-events.jsonl
```

Every hook invocation appends a line with the event, whether it succeeded, and counts including domains matched and rules injected. This is the record that tells you whether hooks are firing at all.

**The gotcha.** The file grows. It is truncated at 10MB, keeping the last 5000 lines, but that truncation runs from the dashboard rather than from the hook writer, so a machine that never opens `base dashboard` has nothing trimming it. Check its size occasionally, or open the dashboard now and then.

## The ladder, in order

<Steps>
  <Step title="Did you type a star command?">
    It short-circuits everything else for that prompt.
  </Step>

  <Step title="Does the domain have rules?">
    `base rule list --domain <name>`. An empty list means the trigger fires into nothing.
  </Step>

  <Step title="Does the trigger match?">
    `base context "<the exact text>"`. Substring matching is literal.
  </Step>

  <Step title="Are you in a registered workspace?">
    `base project list`. Outside one there is no workspace graph to match against.
  </Step>

  <Step title="Is the hook running?">
    Pipe JSON into `base hook <event>` and read stderr.
  </Step>

  <Step title="Is the graph healthy?">
    `base doctor`. It exits nonzero when it is not.
  </Step>
</Steps>

## Next

<CardGroup cols={2}>
  <Card title="Graph health" icon="stethoscope" href="/guides/graph-health">
    What `base doctor` checks, and how to repair or roll back.
  </Card>

  <Card title="Rules and domains" icon="filter" href="/guides/rules-and-domains">
    Getting the trigger right in the first place.
  </Card>
</CardGroup>
