Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,15 +232,15 @@ Built-in English and Traditional Chinese (zh-TW). Locale files in `src/renderer/

## AI Agent Integration

Claude Code is the first conversation workflow, followed by Codex. Install the selected RedLog capture integration in **Settings ▸ Other capture sources ▸ AI Agents**, select its project working directories, then enable new conversations. Installation alone does not start capture or import history. Supported local transcripts supply user messages, AI replies and tool calls/results. This does not cover Claude desktop/web conversations or promise hidden reasoning and image attachments.
Claude Code is the first conversation workflow, followed by Codex. Install the selected RedLog capture integration in **Settings ▸ Other capture sources ▸ AI conversations**, select its project working directories, then enable new conversations. Installation alone does not start capture or import history. Supported local transcripts supply user messages, AI replies and tool calls/results. This does not cover Claude desktop/web conversations or promise hidden reasoning and image attachments.

Shell hooks record terminal commands separately; a shell hook alone does not capture the AI conversation. The API supplies explicit events when needed. See [Capture priority](docs/agent-integration.md#how-ai-conversations-are-recorded).

### Layer 1: Terminal Hooks (Automatic Capture) — start here

Connect your interactive terminal to record its commands and supported output. Non-interactive shells spawned by AI tools may not load shell hooks; use the optional AI transcript integration for their conversation and source-reported tool results.

> **RedLog captures nothing until a source is wired up — being open is not enough.** Install the adapter for each interactive shell. AI capture integrations for Claude Code, Codex and OpenCode are individually optional and uninstalled by default. Install the desired integration in Settings ▸ Other capture sources ▸ AI Agents, add project working directories, then explicitly enable it to record new supported messages and tool calls/results. The Dashboard's **Capture Health** card warns you when nothing is feeding. See [Set up capture](docs/agent-integration.md#set-up-capture--do-this-first).
> **RedLog captures nothing until a source is wired up — being open is not enough.** Install the adapter for each interactive shell. AI capture integrations for Claude Code, Codex and OpenCode are individually optional and uninstalled by default. Parser packages ship as inert offline resources; only the chosen package is installed and loaded after project authorization. Install the desired integration in Settings ▸ Other capture sources ▸ AI conversations, add project working directories, then explicitly enable it to record new supported messages and tool calls/results. The Dashboard's **Capture Health** card warns you when nothing is feeding. See [Set up capture](docs/agent-integration.md#set-up-capture--do-this-first).

**Any agent via shell hook (zsh/bash):**

Expand Down Expand Up @@ -411,7 +411,7 @@ hooks/
command-class.json relayed / pty / native, one list for both readers
plugins/ bundled non-AI capture packs
src/core/plugins/
official-agents.ts optional AI capture catalog, installed only on request
official-agents.ts validates and installs optional offline AI packages
cli/
redlog-cli.js CLI tool for external integration
shell/
Expand Down
25 changes: 20 additions & 5 deletions docs/agent-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ RedLog captures **nothing** until a source is wired up. Being open is not enough

| Source | Covers | How | Only while RedLog open? |
|---|---|---|---|
| **Agent transcript tailer** *(optional)* | New supported Claude Code, Codex or OpenCode transcript content: user/assistant messages and tool calls/results. Thinking is optional and only when present in the source. | Settings ▸ Other capture sources ▸ AI Agents: install one integration, add allowed working directories, then enable it for this project. Each tool is uninstalled by default. | Yes |
| **Agent transcript tailer** *(optional)* | New supported Claude Code, Codex or OpenCode transcript content: user/assistant messages and tool calls/results. Thinking is optional and only when present in the source. | Settings ▸ Other capture sources ▸ AI conversations: install one integration, add allowed working directories, then enable it for this project. Each tool is uninstalled by default. | Yes |
| **Shell hook** | Every command in *your own* terminal (nmap, ffuf, nuclei…): command, exit code, duration, cwd; ordinary Bash/Zsh commands also have bounded output, with native/interactive exceptions | Dashboard **Capture Health ▸ Install shell hook** (or Settings ▸ Commands & terminal), then open a new terminal | Yes — it no-ops when RedLog is closed |
| **mitmproxy (HTTP)** | HTTP/S traffic (the main source for web bounties) | `mitmdump -s /path/to/redlog/hooks/mitmproxy-addon.py` and route your browser through it (or use the one-click Proxied Browser) | Yes |
| **mitmproxy (DNS)** | DNS queries + responses; useful when target resolution matters (subdomain takeover, DoH bypass checks) | `mitmdump --mode dns@5353 -s /path/to/redlog/hooks/mitmproxy-addon.py` — point the target at 127.0.0.1:5353. Root required for port 53. | Yes |
Expand All @@ -51,7 +51,7 @@ RedLog captures **nothing** until a source is wired up. Being open is not enough

### AI project working directories

Each tool has an independent capture integration. In **Settings ▸ Other capture sources ▸ AI Agents**:
Each tool has an independent capture integration. In **Settings ▸ Other capture sources ▸ AI conversations**:

1. Install the capture integration for the desired tool. This does not install the AI tool or contact a model.
2. Add the engagement's working directories with the folder picker.
Expand All @@ -69,7 +69,7 @@ Source locations supported by the current adapters:
| Codex | `~/.codex/sessions/` JSONL |
| OpenCode | `~/.local/share/opencode/storage/` message/part/session files |

These are on-disk source formats, not a guarantee of every vendor version, web/desktop conversation or hidden reasoning. A missing transcript directory requires starting the AI tool and reopening the project. Agent tool results are source-reported evidence; they do not prove that an arbitrary command was independently observed by the shell recorder.
These are on-disk source formats, not a guarantee of every vendor version, web/desktop conversation or hidden reasoning. Source settings can select a nonstandard transcript directory. Defaults honor absolute CLAUDE_CONFIG_DIR (projects/) and CODEX_HOME (sessions/); an explicit project source directory takes precedence. Changing it stops capture until the project is explicitly enabled again. The source directory is separate from allowed working directories. Agent tool results are source-reported evidence; they do not prove that an arbitrary command was independently observed by the shell recorder.

### What records output

Expand Down Expand Up @@ -98,7 +98,7 @@ the ones the engagement uses; neither silently enables the other.

The optional transcript integrations capture newly written supported messages and tool calls/results from Claude Code, Codex and OpenCode. Only source-provided content is available; thinking blocks require a separate opt-in. They are not a substitute for shell output capture.

**Setup:** Install a per-tool integration in Settings ▸ Other capture sources ▸ AI Agents, select allowed working directories, then explicitly enable it for the project. No shell wrapper is required.
**Setup:** Install a per-tool integration in Settings ▸ Other capture sources ▸ AI conversations, select allowed working directories, then explicitly enable it for the project. No shell wrapper is required.

**What it captures:**

Expand All @@ -111,7 +111,7 @@ The optional transcript integrations capture newly written supported messages an
| `transcript_snapshot` | Cumulative SHA-256 of the sidecar file (emitted on 15 s idle or session close) |
| `transcript_compacted` | Emitted when Claude Code `/compact` runs |

**Sidecar files:** The tailer writes a copy of each session's events to `<projectDir>/agent-transcripts/<kind>-<session>-<activation>.jsonl`. A separate start-offset checkpoint plus the sidecar size locate the read offset; restarting the same activation does not re-import history.
**Sidecar files:** The tailer writes a copy of each session's events to `<projectDir>/agent-transcripts/<kind>-<session>-<activation>.jsonl`. A separate durable source-offset checkpoint locates the read position independently of retained sidecar bytes; restarting the same activation does not re-import history.

**Redaction:** `deepRedactStrings()` walks every string value; paths matching `.ssh/`, `.env`, `.aws/` suppress the output field entirely.

Expand Down Expand Up @@ -358,3 +358,18 @@ This gives you:
- Agent-initiated markers and scope checks (API / shell functions)
- Team-shared scope configuration (profiles)
- Per-operator attribution + Bitcoin-backed integrity anchoring


Pause omits new AI originals from both the event log and raw sidecar; resume
skips bytes already present at that boundary. A metadata-only capture gap
records the omission. In AI source settings, expand Conversations to stop one
session or explicitly allow new content. Exclusions persist per project and
provider; allowing again does not import the excluded period. Working-directory
authorization does not classify prompts or hide a tool's reads outside that
directory.

After an app update, an intact older optional package offers Update integration
in the source row; it cannot execute until updated. Unknown or modified files
remain refused and available for inspection. Installing/updating never grants
a new project authorization. The separate installation records live alongside
the user plugin directories and are not captured evidence.
31 changes: 31 additions & 0 deletions docs/domain/SPEC-capture-source-lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,34 @@ The runtime and health projection use `resolveAgentCapture`. The settings source
Adapter initialization, main/auxiliary watchers and delayed callbacks share activation/project boundaries. Disable, uninstall and project switch stop those watchers before replacing project identity. Rejected sessions create no sidecar. Existing JSONL sessions begin at the EOF observed on connection; the checkpoint records skipped source bytes and requested activation time. New source files created after activation may begin at byte zero. Recorded evidence is retained on disable/uninstall.

Only data exposed by the supported local transcript format is captured. Source-reported tool calls/results are distinct from independently observed shell execution and output. No promise is made to recover hidden reasoning, all historical sessions, or every vendor storage version.

## Optional AI code packages

Provider parsing code is an optional package, separate from the shared capture host. The shipped catalog is inert: listing sources or installing a package MUST NOT execute its parser or grant project access. Only a valid, active installation with explicit working-directory permission and activation boundary may load a provider module. Stop, uninstall and project switch MUST stop all provider watchers and discard its registered adapter/module instance. Captured evidence and original vendor transcripts survive removal.

Source identity and default/environment directory mappings come from package metadata. Runtime, source detection and health MUST resolve the same source location. An explicitly selected source directory is not an allowed cwd; changing either permission range or source location stops recording pending confirmation, preserving from-now behavior. Unknown or modified executable files MUST NOT execute merely because a manifest has an official-looking ID. This release accepts only exact app-supplied package bytes; it does not authorize arbitrary third-party in-process parsers.


AI pause is a preservation boundary: new original conversation bytes must not
be written to events or sidecars while paused. Resume skips the then-existing
source range (including delayed file notifications and crossing partial
lines); durable offset/disposition metadata and capture_gap may describe the
omission without storing its text. A persisted paused boundary fails closed
across reopening. Event writes, raw append and progress commit are separate;
failed units remain retryable, and restart dedup keys use AI data.session_id,
not RedLog's envelope session ID. Pending-parent replay uses retained raw
bytes, not conversation copies in checkpoint metadata.

Individual AI exclusions are keyed by project, provider and session. They do
not widen working-directory authorization. Reauthorizing a conversation or
source begins at the later applicable activation boundary. The registry's
empty default still permits cwd-authorized sessions; it is not per-conversation
consent. Cwd authorization includes the conversation's tool content even if a
tool reads outside that cwd; no content classifier claims to identify private
prompts. Source UI exposes observed sessions and their explicit exclusions.

Official AI package installations have separate machine installation records.
Intact recorded packages can be removed or explicitly updated after an app
update; only the current app-supplied bytes may load. Unknown/modified packages
are preserved and refused. Updating preserves prior installation identity but
does not create or widen project recording permission.
28 changes: 16 additions & 12 deletions e2e/capture-settings-interaction.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ test('external-source running and failed IPC reads remain distinct in settings',
} finally { await app.close() }
})

test('other-source settings link to disabled plugins and require explicit AI scope activation', async () => {
test('optional AI recovers in its source entry and requires explicit project authorization', async () => {
const { app, page, tmpHome } = await launchWithTempHome()
try {
const first = join(tmpHome, 'client-work')
Expand All @@ -189,7 +189,14 @@ test('other-source settings link to disabled plugins and require explicit AI sco
localStorage.setItem('redlog-locale', 'en')
const result = await window.redlog.plugins.installOfficialAgent('codex')
if (!result.ok) throw new Error(result.error)
await window.redlog.plugins.setEnabled('official-ai-codex', false)
})
await app.evaluate((_electron, home) => {
const fs = process.getBuiltinModule('fs')!
const path = process.getBuiltinModule('path')!
fs.writeFileSync(path.join(home, '.redlog', 'plugins', 'state.json'), JSON.stringify({ disabled: ['official-ai-codex'] }))
}, tmpHome)
await page.evaluate(async () => {
await window.redlog.plugins.reload()
})
await page.reload()
await openView(page, 'settings')
Expand All @@ -198,32 +205,29 @@ test('other-source settings link to disabled plugins and require explicit AI sco
await other.click()
const before = await page.evaluate(() => window.redlog.config.get())
const row = page.getByTestId('agent-source-codex')
await row.getByRole('button', { name: 'Go to plugin settings' }).click()
await expect(page.locator('[data-settings-page="plugins"]')).toHaveAttribute('aria-current', 'page')
expect((await page.evaluate(() => window.redlog.plugins.list())).find(p => p.id === 'official-ai-codex')?.status).toBe('disabled')
expect(await page.evaluate(() => window.redlog.config.get())).toEqual(before)
// Explicitly enable the integration through the existing plugin control.
await page.getByRole('button', { name: 'Enable', exact: true }).click()
await row.getByTestId('agent-restore-codex').click()
await expect.poll(async () => (await page.evaluate(() => window.redlog.plugins.list())).find(p => p.id === 'official-ai-codex')?.status).toBe('active')
await expect(page.locator('[data-settings-page="captureControl"]')).toHaveAttribute('aria-current', 'page')
expect(await page.evaluate(() => window.redlog.config.get())).toEqual(before)
await page.getByRole('button', { name: 'Plugins', exact: true }).click()
await expect(page.getByText('Codex CLI', { exact: true })).toHaveCount(0)
await other.click()
const setPicker = async (path: string) => app.evaluate(({ ipcMain }, next) => {
ipcMain.removeHandler('hookConfig:pickPath')
ipcMain.handle('hookConfig:pickPath', () => next)
}, path)
await setPicker(first)
await row.getByTestId('agent-add-path-codex').click()
const hint = row.getByText('These working directories are not being recorded yet.', { exact: false })
await expect(hint).toBeVisible()
const checkbox = row.getByTestId('agent-enabled-codex')
await expect(checkbox).toBeEnabled()
await expect(checkbox).not.toBeChecked()
await checkbox.check()
await expect(hint).toHaveCount(0)
await expect.poll(async () => (await page.evaluate(() => window.redlog.config.get())).agentTailer?.sources?.codex?.enabled).toBe(true)
await setPicker(second)
await row.getByTestId('agent-add-path-codex').click()
// The scope moved under a recording source: the row says so, and the one
// control that resolves it is the same checkbox, relabelled.
const scopeChanged = row.getByText('Scope changed', { exact: false })
const scopeChanged = row.getByTestId('agent-scope-changed-codex')
await expect(scopeChanged).toBeVisible()
await expect(row.getByText('Confirm this range and record')).toBeVisible()
await expect(checkbox).not.toBeChecked()
Expand Down
Loading
Loading