diff --git a/README.md b/README.md index 2fa134a330..0bb7c67206 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ With Entire, you can: - **Understand why code changed, not just what** — Transcripts, prompts, files touched, token usage, tool calls, and more are captured alongside every commit. - **Rewind and resume from any checkpoint** — Go back to any previous agent session and pick up exactly where you or a coworker left off. - **Full context preserved and searchable** — A versioned record of every AI interaction tied to your git history, with nothing lost. -- **Zero context switching** — Git-native, two-step setup, works with Claude Code, Codex, Gemini, and more. +- **Zero context switching** — Git-native, two-step setup, works with Claude Code, Codex, Gemini, Pi, and more. ## Table of Contents @@ -359,6 +359,7 @@ Each agent stores its hook configuration in its own directory. When you run `ent | Factory AI Droid | `.factory/settings.json` | JSON hooks config | | Gemini CLI | `.gemini/settings.json` | JSON hooks config | | OpenCode | `.opencode/plugins/entire.ts` | TypeScript plugin | +| Pi | `.pi/extensions/entire/index.ts` | TypeScript extension | You can enable multiple agents at the same time — each agent's hooks are independent. Entire detects which agents are active by checking for installed hooks, not by a setting in `settings.json`. @@ -435,6 +436,7 @@ Local settings override project settings field-by-field. When you run `entire st - When enabling Entire for Codex, the command will also create or update `.codex/config.toml` with `codex_hooks = true` to enable Codex hooks. If you configure Codex manually, make sure this flag is set in your `.codex/config.toml`. Or select Codex from the interactive agent picker when running `entire enable`. - Entire supports Cursor IDE and Cursor Agent CLI tool, but `entire rewind` is not available at this time. Other commands (`doctor`, `status` etc.) work the same as all other agents. - Entire supports Copilot CLI, but not Copilot in VS Code, in other IDEs, or on github.com. +- Entire supports Pi coding agent (Preview). Pi uses a TypeScript extension instead of a JSON hook config. Subagent capture is not currently available. ## Security & Privacy diff --git a/docs/architecture/agent-guide.md b/docs/architecture/agent-guide.md index 031c9eb48b..69dc86178f 100644 --- a/docs/architecture/agent-guide.md +++ b/docs/architecture/agent-guide.md @@ -568,6 +568,24 @@ Key difference: OpenCode stores transcripts in a database, not files. The transc **Position:** Message count (`len(session.Messages)`). **Offset:** Start iterating messages at index N. +### JSONL Format (Pi pattern) + +Pi uses JSONL (one JSON object per line) with a tree-shaped entry model. Every entry has `id` and optional `parentId`, enabling Pi's `/fork` and `/clone` branching. Each entry has `type` (`"message"` for conversational entries), `timestamp`, and (for message entries) a `message` object with `role`, `content`, and optional `usage`: + +``` +{"type":"message","id":"abc123","parentId":"xyz789","timestamp":"...","message":{"role":"user","content":"Fix the bug"}} +{"type":"message","id":"def456","parentId":"abc123","timestamp":"...","message":{"role":"assistant","content":[...],"usage":{"input":100,"output":200,"cacheRead":0,"cacheWrite":50}}} +``` + +User `content` can be a plain string or an array of content blocks (text, toolCall, toolResult). `usage` carries `input`, `output`, `cacheRead`, and `cacheWrite` token counts on assistant messages. + +**Active branch resolution**: Because Pi sessions form a tree, the transcript accumulates entries from both active and abandoned branches. Entire's `pijsonl.ResolveActiveBranch()` walks the `parentId` chain from the last message to the root. Only entries on the active branch contribute to token counts, file lists, and extracted prompts. + +**Chunking:** Use `agent.ChunkJSONL(content, maxSize)` — splits at newline boundaries. +**Reassembly:** Use `agent.ReassembleJSONL(chunks)` — concatenates with newlines. +**Position:** Line count (via `pijsonl.CountLines`). +**Offset:** Start parsing at line N (via `pijsonl.SkipLines`). + ### JSONL Format (Factory AI Droid pattern) Similar to Claude Code's JSONL format (one JSON object per line), but with a different envelope structure. Factory AI Droid wraps messages as: @@ -701,6 +719,22 @@ Note: Cursor uses camelCase hook names in `.cursor/hooks.json` and provides a `c Note: Factory AI Droid uses PascalCase hook names in `.factory/settings.json` with a nested `matcher`/`hooks` structure. The `matcher` field scopes which tool triggers the hook (empty string = all tools). `SessionStart` includes a second `user-prompt-submit` entry to ensure `TurnStart` fires in droid exec mode where `UserPromptSubmit` doesn't fire. `PreToolUse`/`PostToolUse` use `"matcher": "Task"` to scope to subagent tracking. +### Plugin File Pattern (Pi) + +Pi uses a TypeScript extension file (`.pi/extensions/entire/index.ts`) instead of a JSON config. The extension is embedded in the Go binary via `//go:embed` and installed by `entire enable --agent pi`. + +Pi extension hooks fire via `execFile` (non-blocking) to avoid blocking the agent. The extension listens for Pi lifecycle events (`session_start`, `before_agent_start`, `agent_end`, `session_shutdown`) and dispatches each to `entire hooks pi ` with a JSON payload containing `type`, `cwd`, `session_file`, `session_id`, and (for `before_agent_start`) `prompt`. + +Key differences from JSON config agents: +- Extension file is written/removed entirely (not partial JSON edits) +- Uses `node:child_process.execFile` for all hook invocations +- Session ID is cached to `.entire/tmp/pi/pi-active-session` to bridge races between `session_start` and `before_agent_start`/`agent_end` +- On `agent_end`, the Pi JSONL transcript is captured to `.entire/tmp/pi/.json` for stable reference even if native Pi sessions are deleted +- `session_shutdown` is cleanup-only (no `SessionEnd` event) to avoid a race with `agent_end`'s checkpoint save +- Idempotency via marker string check: `"Auto-generated by \`entire enable --agent pi\`"` + +See `cmd/entire/cli/agent/pi/entire_extension.ts` for the full extension source. + ### Plugin File Pattern (OpenCode) OpenCode uses a TypeScript plugin file (`.opencode/plugins/entire.ts`) instead of a JSON config. The plugin is auto-generated by `entire enable --agent opencode` and uses OpenCode's Bun-based plugin API. diff --git a/docs/architecture/agent-integration-checklist.md b/docs/architecture/agent-integration-checklist.md index 22b9caa835..18ebacb3af 100644 --- a/docs/architecture/agent-integration-checklist.md +++ b/docs/architecture/agent-integration-checklist.md @@ -45,7 +45,7 @@ See Guide: [Transcript Format Guide](agent-guide.md#transcript-format-guide), [T - [ ] **Full transcript on every turn**: At turn-end, capture the complete session transcript, not just events since the last checkpoint - [ ] **Resumed session handling**: When a user resumes an existing session, the transcript must include all historical messages, not just new ones since the plugin/hook loaded -- [ ] **Use agent's canonical export**: Prefer the agent's native export command (e.g., reading Claude's JSONL file, Gemini's JSON, Cursor's JSONL, Factory AI Droid's JSONL, Copilot CLI's JSONL, OpenCode's `opencode export` JSON) over manually reconstructing from events +- [ ] **Use agent's canonical export**: Prefer the agent's native export command (e.g., reading Claude's JSONL file, Gemini's JSON, Cursor's JSONL, Factory AI Droid's JSONL, Copilot CLI's JSONL, OpenCode's `opencode export` JSON, Pi's JSONL session file) over manually reconstructing from events - [ ] **No custom formats**: Store the agent's native format directly in `NativeData` - do not convert between formats (e.g., JSON to JSONL) or create intermediate representations - [ ] **Graceful degradation**: If the canonical source is unavailable (e.g., agent shutting down), fall back to best-effort capture with clear documentation of limitations @@ -54,7 +54,7 @@ See Guide: [Transcript Format Guide](agent-guide.md#transcript-format-guide), [T See Guide: [Step 3 - Core Agent Interface](agent-guide.md#step-3-implement-core-agent-interface-youragentgo) - [ ] **`WriteSession` implementation**: Agent must implement `WriteSession(AgentSession)` to restore sessions -- [ ] **File-based agents** (Claude, Gemini, Cursor, Factory AI Droid, Copilot CLI): Write `NativeData` to `SessionRef` path +- [ ] **File-based agents** (Claude, Gemini, Cursor, Factory AI Droid, Copilot CLI, Pi): Write `NativeData` to `SessionRef` path - [ ] **Database-backed agents** (OpenCode): Write `NativeData` to file, then import into native storage (the native format should be what the agent's import command expects) - [ ] **Single format per agent**: Store only the agent's native format in `NativeData` - no separate fields for different representations of the same data diff --git a/docs/security-and-privacy.md b/docs/security-and-privacy.md index 284b370197..5b901d6cc4 100644 --- a/docs/security-and-privacy.md +++ b/docs/security-and-privacy.md @@ -6,7 +6,7 @@ Entire stores AI session transcripts and metadata in your git repository. This d ### Where data is stored -When you use Entire with an AI agent (Claude Code, Codex, Gemini CLI, OpenCode, Cursor, Factory AI Droid, Copilot CLI), session transcripts, user prompts, and checkpoint metadata are committed to a dedicated branch in your git repository (`entire/checkpoints/v1`). This branch is separate from your working branches, your code commits stay clean, but it lives in the same repository. +When you use Entire with an AI agent (Claude Code, Codex, Gemini CLI, OpenCode, Cursor, Factory AI Droid, Copilot CLI, Pi), session transcripts, user prompts, and checkpoint metadata are committed to a dedicated branch in your git repository (`entire/checkpoints/v1`). This branch is separate from your working branches, your code commits stay clean, but it lives in the same repository. Entire also creates temporary local branches (e.g., `entire/`) as working storage during a session. Metadata written to these shadow branches — transcripts, prompts, incremental checkpoint data, subagent transcripts — goes through the same redaction pipeline as `entire/checkpoints/v1`. **Code-file snapshots, however, are written as raw blobs of your working tree without redaction**, so any hardcoded secrets in your source code would appear unredacted on the shadow branch. Gitignored files (e.g., `.env`) are filtered out of these snapshots as a partial defense. Shadow branches are **not** pushed by Entire; do not push them manually, because unredacted source content would be visible on the remote. They are cleaned up when session data is condensed into `entire/checkpoints/v1` at commit time.