# Redaction

> Replace known secret patterns in archived conversation text, preview rules, and understand what redaction does not cover.

Redaction replaces text that matches known secret patterns, such as API keys
and private keys, before it enters the archive's conversation files. It is
pattern matching, not a review. Secrets that match no rule, file paths, and
ordinary sentences stay as they are.

- App: **Settings → Privacy & Sharing**
- CLI: `hansard redact`

## What redaction covers

| Data                                                                              | Redaction                                                                                                                                                                                   |
| --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Conversation text, tool calls, and tool output in the archive                     | Matching text becomes a marker such as `[REDACTED AWS ACCESS KEY ID]`.                                                                                                                      |
| Original harness files kept with each conversation                                | Not redacted. Hansard keeps them byte for byte. The exceptions are OpenCode and MiMo Code, whose copies leave out stored credentials and share secrets. The archive records each exception. |
| The reveal cache, which keeps the original form of each message redaction changed | Not redacted, by design. It stays on this machine.                                                                                                                                          |
| Attachments and captured artifacts                                                | Not inspected or redacted.                                                                                                                                                                  |
| Conversations in a repository on the allowlist                                    | Not redacted.                                                                                                                                                                               |

The built-in rules detect:

| Rule               | Matches                                                                                                                                   |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `aws_key`          | AWS access key IDs                                                                                                                        |
| `anthropic_key`    | Anthropic API keys                                                                                                                        |
| `openai_key`       | OpenAI API keys                                                                                                                           |
| `github_token`     | GitHub tokens                                                                                                                             |
| `slack_token`      | Slack tokens                                                                                                                              |
| `jwt`              | JSON Web Tokens                                                                                                                           |
| `private_key`      | PEM private key blocks                                                                                                                    |
| `high_entropy_env` | Random-looking values assigned to variables whose names contain words such as `KEY`, `TOKEN`, `SECRET`, or `PASSWORD`                     |
| `bearer_token`     | Random-looking credentials after `Bearer` in an Authorization header, such as the token in an agent's MCP entry. The word `Bearer` stays. |

Slack posts and Team uploads use the redacted text. Personal Sync also uploads
the original harness files, which are never redacted. Labeling and
conversation summaries remove common secret patterns from what they send to a
model even when archive redaction is off.

## Review local exposure in the app

1. Open **Settings → Privacy & Sharing**.

2. Check **Keep unredacted copies**. When it is on, Hansard keeps the
   original form of each message redaction changes on this computer, so
   `hansard show --unredacted` and `hansard redact reapply` can rebuild a
   conversation as it was before redaction. A conversation redaction leaves
   unchanged needs nothing kept, since its archived transcript already holds
   every message as it was.

3. Under **Sharing**, check whether Personal Sync, Teams, Slack, or
   Classification can send conversations off this computer.

4. Open a representative conversation and expand its messages, tool results,
   and attachments. Redaction markers show where a rule matched. Their absence
   does not mean the conversation is free of sensitive data.

Rules, previews, and reapplying redaction are CLI tasks, because they edit
`redaction.yaml` and can rewrite archived conversations.

## Turn on redaction

New installations set up with `hansard init` turn on the built-in rules unless
you pass `--no-redaction`. The app's setup selects **Redact common secrets**
by default. Otherwise redaction stays off until you create a configuration.

Check the current state before you import sensitive history:

```sh
hansard redact status
```

To create or turn on the configuration:

```sh
hansard redact init
```

Hansard writes `~/.hansard/redaction.yaml`, or the same file under
`HANSARD_HOME`.

## Preview rules

Previews never change the archive, and they work even while redaction is off.
Matches in the output are masked.

```sh
hansard redact test --text 'DEMO_SERVICE_TOKEN=0123456789abcdefghijklmnopqrstuvwxyzABCDEF'
hansard redact test --file ./synthetic-session.txt
hansard redact test --session <session-id>
```

Import or reimport only after the preview matches what you expect.

## Customize redaction.yaml

```yaml
enabled: true

built_ins:
  jwt: false

env_vars:
  - DEMO_SERVICE_TOKEN

patterns:
  - name: example_ticket
    regex: 'DEMO-[0-9]{4}'

allowlist_repos: []
```

| Key               | Effect                                                                                                                                                                                                                                          |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`         | Turns redaction on or off.                                                                                                                                                                                                                      |
| `built_ins`       | Turns individual built-in rules on or off. All are on by default.                                                                                                                                                                               |
| `env_vars`        | Variable names whose exact values Hansard replaces. It reads each value from its own environment and from `.env` files in the conversation's folder and its parents, up to the repository root. The value is never written to `redaction.yaml`. |
| `patterns`        | Your own regular expressions, applied after the built-in rules.                                                                                                                                                                                 |
| `allowlist_repos` | Repositories whose conversations skip every rule.                                                                                                                                                                                               |

Test custom patterns against made-up text before you import a large archive.

> **An allowlisted repository is not redacted:** Every rule is skipped for conversations in a repository listed under
> `allowlist_repos`. Use it only when exact text matters more than the
> protection redaction gives.

## Turn rules on or off

```sh
hansard redact enable
hansard redact disable
hansard redact disable jwt
hansard redact enable jwt
```

Without a rule name, the command turns redaction as a whole on or off. With a
rule name, it changes only that rule. Run `hansard redact status` after any
change.

## Apply rules to existing conversations

New rules apply to conversations imported from then on. To rewrite
conversations already in the archive:

```sh
hansard redact reapply
```

Reapply rewrites a conversation only when the reveal cache can rebuild it as
it was before redaction: from the originals kept of the messages redaction
changed, or from its archived transcript when redaction changed nothing. It
skips conversations received from other devices, conversations not tied to a
repository (such as imported web chats), conversations whose originals were
not kept, and conversations a newer version of Hansard archived, and reports
how many it skipped.

Reapply does not change:

- the original harness files kept in the archive, even when the harness has
  since removed its own copy;
- what the import recorded about a conversation beyond its messages, such as
  its kind, title, and provider summary;
- other conversations read from the same harness file;
- attachments or artifacts;
- copies already uploaded to Personal Sync or a Team;
- messages already posted to Slack; or
- the harness's own history files.

If the harness still has its history, a full reimport of that source is
another way to apply new rules. See [Maintenance](https://www.hansard.dev/reference/maintenance/).
