Metadata-Version: 2.5
Name: akritrim-colab
Version: 0.1.66
Summary: Three-party AI collaboration TUI for Codex, Claude, and the user
Project-URL: Homepage, https://github.com/akritrim/akritrim-colab
Project-URL: Issues, https://github.com/akritrim/akritrim-colab/issues
Author: Chandan Ranjan
License: MIT
License-File: LICENSE
Keywords: ai,claude,codex,collaboration,tui
Classifier: Environment :: Console
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Software Development :: User Interfaces
Requires-Python: >=3.11
Requires-Dist: rich>=13.0.0
Requires-Dist: textual>=8.0.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# akritrim-colab

A three-pane collaboration TUI that puts you between Claude and Codex inside any repository. You direct, they implement and review.

Proudly made by Claude code, Codex and me :)
> Requires [Claude CLI](https://docs.anthropic.com/en/docs/claude-code) and [Codex CLI](https://github.com/openai/codex) installed and authenticated.

## Demo Video
https://github.com/user-attachments/assets/fa969809-ceba-4762-aa98-525625b0d9ef

## Install

```bash
pip install akritrim-colab
```

Or, for an isolated CLI install:

```bash
pipx install akritrim-colab
```

## Quick Start

```bash
cd /path/to/your-repo
akritrim-colab
```

On first run, collaboration files are scaffolded into `.collab/`. Then the TUI launches.

## Layout

| Pane | Contents |
|------|----------|
| Left | Shared session chat |
| Upper right | Claude output |
| Lower right | Codex output |
| Bottom | Master input |

**Resizing panes:** Two draggable dividers let you adjust the layout:
- **Vertical divider** (between chat and agent panels) — drag left/right to give more space to the chat or to the agent output columns
- **Horizontal divider** (between Claude and Codex panels) — drag up/down to give more space to Claude or Codex output

Click and hold on a divider, then drag to resize. The layout adjusts in real time.

## Input

| Key | Action |
|-----|--------|
| `Enter` | Send message |
| `Ctrl+Enter` | Insert newline |
| `Tab` | Accept autocomplete suggestion |
| `↑` / `↓` | Browse command history or navigate autocomplete |
| `Escape` | Cancel active agent work |
| `Ctrl+C` | Copy the mouse-selected text if any, otherwise quit |

Drag with the mouse inside the chat, Claude, Codex, or diff panes to select text. It is copied to the clipboard as soon as you release the mouse (`copy_on_select`, on by default), and `Ctrl+C` copies it again. While text is selected, new output in the Claude and Codex panes is held and appears once the selection is cleared (after copying, or by clicking elsewhere); the chat pane keeps appending but stops auto-scrolling. Panes only auto-follow new output when you are already scrolled to the bottom, so you can scroll up and read while an agent works.

Type `/` to open the command autocomplete palette.

## Routing

Direct a message to a specific agent:

```
@claude propose a UI improvement
@codex review the current changes
@both compare these two approaches
```

Or use `/ask` for a one-off direct message without changing the default routing:

```
/ask claude explain this function
/ask codex run the tests
/ask both what are the risks here
```

## File Mentions

Inject file content directly into your message using `@path/to/file`:

```
@claude refactor this — @src/auth.py
@both compare the two implementations: @src/v1.py and @src/v2.py
```

The TUI expands the token at submit time. The agent receives the file content inline — no need to ask the agent to read it separately.

**Line limit:** Files over 150 lines are automatically truncated. A notice is appended showing how many lines were omitted and how to use a range:

```
[first 150 of 892 lines — 742 lines omitted. Use @src/auth.py:START-END for a specific range.]
```

**Line ranges:** Inject a specific section of a file:

```
@src/auth.py:40-80        lines 40 to 80 inclusive
```

The header shows `(lines 40–80 of 892)` so the agent knows the context position. The end of the range is clamped to the actual file length.

**Safety guards:**
- Path must resolve inside the repository root — `@../../etc/passwd` is blocked
- Files over 50 KB are skipped entirely
- Binary files (null bytes) are skipped
- `@claude`, `@codex`, `@both`, `@master` are never treated as file paths

## Work Flows

Structured multi-agent flows that coordinate Claude and Codex automatically:

```
/fix <bug>           isolate → patch → review
/audit <target>      independent dual review → merged typed findings → cross-check
/review [scope]      Codex built-in review (read-only) → Claude triages findings
/race <task>         both agents implement it in separate copies; you pick one
/feature <desc>      design → implement → review
/refactor <target>   map call sites → refactor → verify
/analyze <question>  dual analysis + position comparison
/decide <text>       log a decision to collaboration memory
```

`/audit` asks Claude and Codex for typed findings (severity, file, line, title, detail), matches the two lists, and then has each agent verify the findings only the other reported. The chat shows one list tagged `confirmed` (both agents, or the other agent agreed), `disputed` or `unverified`, and the result is saved to `.collab/session/findings.json`. Codex runs read-only for audits. If structured output ever fails, `/audit --prose <target>` runs the older free-text comparison.

`/review` accepts one scope — `--uncommitted` (default), `--base <branch>`, or `--commit <sha>` — or free-text review focus (Codex cannot combine a scope with custom instructions). Codex runs `codex exec review` in a read-only sandbox, then Claude checks each finding as VALID or INVALID and fixes the valid ones.

## Models, Effort and Usage

```
/model                           show each agent's model
/model claude <id|default>       change Claude's model for this run
/model codex <id|default>        change Codex's model for this run
/effort claude <level|default>   low | medium | high | xhigh | max
/effort codex <level|default>    passed to Codex as model_reasoning_effort
```

Changes apply from the next turn and last until you quit; to keep them, set `claude_model`, `codex_model`, `claude_effort`, `codex_effort` or `claude_fallback_model` (a model, or a comma-separated list, tried when the main one is overloaded) in `.collab/settings.toml`.

The status bar shows the app version and, once agents have run, their token use this session, for example `claude 42.2k in/955 out ~$0.10 | codex 95k in/2.3k out`. Claude reports an estimated cost; Codex reports tokens only, so no cost is shown for it. Counts reset when you quit.

```
/settings                        open the settings picker: every setting with what it does, its effect and when it applies
/settings list                   print all settings with descriptions in the chat
/settings status_bar_items       choose which status bar items are shown (and in what order); `models` shows each agent's model/effort
/settings <name> [value|default] show a setting with its options, or change it (saved to .collab/settings.toml)
/gate                            show what the approval gate protects
/gate legacy claude              turn Claude's pre-execution gate off for this run (loud in the status bar)
/gate required claude            turn it back on (verified again on Claude's next turn)
/gate legacy codex               Codex back to `codex exec` with a notice after the command ran
/gate required codex             Codex's pre-execution gate on again
```

The status bar also shows the gate state, for example `gate claude=ON codex=ON`; see [Dangerous Operation Enforcement](#dangerous-operation-enforcement).

### Race mode

`/race <task>` gives Claude and Codex the same task and lets them work at the same time, each in its own private git worktree of your last commit (under `.collab/session/race/`). Both agents are instructed to work only inside those copies, and the app changes your files only when you pick a result. One caveat: Claude is not sandboxed and is only told to stay in its copy, so when the race finishes (or is cancelled) the TUI runs a limited check of your working tree and warns you if something changed. The check is `git status`, so it cannot see ignored files or changes inside `.git`, and if the check itself fails you get a warning to look yourself.

```
/race <task>              start (needs a clean working tree and at least one commit)
/race pick claude|codex   apply that agent's result to your working tree
/race discard             throw both results away
/race status              show the pending race
/race clean               remove leftovers from a crashed run
```

When both finish, each pane shows `[DIFF]` links for the files that agent changed and the chat shows a one-line summary per agent (files changed, lines added and removed). `pick` applies the winner as uncommitted changes: nothing is staged or committed, and if your files changed in the meantime and the patch no longer applies cleanly, nothing is changed and you can pick the other result. Press `Escape` to cancel a race at any point, including while the results are being collected; its copies are removed. If a cancel arrives while git is still collecting results and it does not finish within 30 seconds, the copies are left in place with a warning rather than removed from under git; `/race clean` removes them later, and skips any folder git is still working in until that finishes.

Limits: both agents start from the last commit, so uncommitted work is refused rather than silently left out. Race agents cannot ask you for approval, so a Claude step that needs one (such as `git push`) ends that agent's attempt. Codex is confined to its worktree by its sandbox; Claude is not sandboxed and is only told to stay inside its directory, which is why the working-tree check exists (it can flag some stray writes; it cannot prevent one and is not proof that nothing changed). A race reply never replaces what the chat remembers from each agent, and cancelling a race leaves the chat's state alone.

## Session Commands

```
/fresh                   start a new session (clears history)
/resume                  resume from last saved state
/status                  show current session state
/save                    persist session state to disk
/exit                    exit the TUI
```

## Dangerous Operation Enforcement

Certain operations require your explicit approval before an agent executes them:

```
git push (any form)        git tag
npm publish / npm pack     twine upload
pip install --user         rm -rf
docker push                kubectl apply / kubectl delete
CI/CD pipeline file edits  (.github/workflows/, .gitlab-ci.yml, Jenkinsfile)
```

**Claude (approval gate, on by default):** Claude Code asks the TUI *before* it runs a shell command or changes a file. If the call matches a dangerous operation, a full-screen approval dialog appears and Claude waits for your answer:
- `y` or the Approve button — allows that specific command and continues
- `n`, `Escape`, or the Deny button — blocks it; Claude is told it was blocked and not to look for a way around

Each approval covers exactly one call: if Claude later runs the same `git push origin main` again, you are asked again, and approving one command never approves another. Nothing remembered from earlier (including a command Codex already ran, which only produces a notice) lets a Claude call through unasked. CI/CD file edits are enforced through Claude's file tools (`Write`, `Edit`, `NotebookEdit`) using the real, resolved path, so `./x/../Jenkinsfile` or a symlinked folder does not slip past; a shell command that both mentions a CI file and looks like it writes (`sed -i`, `cp`, `>`, ...) also asks.

The gate is checked before any task is sent. Claude is started with no prompt, and the task is written only after the approval hook has reported to the TUI with a one-time code; a short test run once per app launch also proves the hook really intercepts tool calls. If the gate cannot be established (hooks not loaded, Claude Code older than 2.1.295, the private socket cannot open), **the turn does not run** and you get an error saying why. It never downgrades by itself. Switch deliberately with `/gate legacy claude` (shown loudly in the status bar as `claude=LEGACY`) or `claude_approval_gate = "legacy"`; `/gate required claude` turns it back on.

Limits, stated plainly: shell-command matching is pattern based, so a determined or unlucky command can evade it (variables, globs, interpreters); tools reached through MCP servers are not covered; and Claude Code's own protections are not relied on. Race attempts (`/race`) cannot ask you, so gated operations there are denied. For the same reason, if you turn `codex_ask_every_command` on, Codex's race attempt is not started; set `codex_race_without_dialogs = true` to let it run ordinary commands in its sandboxed copy without a dialog (dangerous operations, CI-file edits and requests marked as extra access stay blocked), or race with `/gate legacy codex`.

**Codex (approval gate, on by default):** writable Codex turns run through `codex app-server` with the `untrusted` approval policy, so every command or file change Codex does not consider known-safe is sent to the TUI *before* it runs. Dangerous operations and CI-file edits open the same approval dialog as for Claude (one call per approval); a request that carries a reason for extra access, a network target or a write outside its folder also asks you, and a malformed network request is declined. By default other commands run without a dialog inside Codex's workspace sandbox, as with Claude (`codex_ask_every_command = false`). Codex does not reliably mark every request to leave its sandbox, so for strict protection set `codex_ask_every_command = true` to be asked about every command Codex wants approved (many more dialogs). Same rules as Claude: the gate is verified before the task is sent (version check plus one short test run per app launch), and if it cannot be established **the turn does not run**; switch deliberately with `/gate legacy codex` or `codex_approval_gate = "legacy"` (then Codex only gets a `⚠ POST-EXEC` notice after the fact, and the status bar says `codex=advisory`). Read-only turns (`/audit`, `/review`, the reviewer read-only setting) run in a read-only sandbox and need no gate. App-server is marked experimental by OpenAI; it was verified against Codex 0.163.0.

The permission policy is also injected into every agent prompt, asking both agents to request `Master: requesting permission to ...` before executing dangerous operations.

To configure which operations are gated, see the `dangerous_ops` key in [Configuration](#configuration) below.

## Agent Control

```
/approve                 approve a pending agent request
/deny                    deny a pending agent request
/compare                 run a manual comparison round between agents
/mode <value>            broadcast a mode change to both agents
/role <target> <role>    reassign agent roles at runtime
```

Role targets: `claude`, `codex`, `both`. Role values: `implementer`, `reviewer`, `collaborator`.

Example:
```
/role codex implementer
/role both reviewer
```

## Collaboration Memory

```
/decision D-XXX | Title | Decision | Rationale    log a structured decision
/topic T-XXX | Title | Codex pos | Claude pos      open a scratchpad topic
/resolve-topic T-XXX | D-XXX                       mark a topic resolved
```

Decisions are appended to `.collab/memory.md`. Topics go to `.collab/scratchpad.md`. Both files are read by agents at session start and on update.

## Export

```
/export claude session_claude.txt     export Claude pane to file
/export codex session_codex.txt       export Codex pane to file
/export master session_chat.txt       export the shared chat to file
```

## Diff Viewer

After each agent turn, `▶ [DIFF] <file>` links appear inline for every file the agent changed. Each link is permanently bound to the exact patch from that turn — later edits to the same file do not overwrite earlier diff history.

- Click a link to open a full-screen diff overlay (colour-coded: `+` green, `-` red, `@@` cyan)
- Click `⎘ Copy` to copy the raw diff to the clipboard
- Click `X` to close

## Themes

```
/theme akritrim    (default)
/theme nord
/theme dracula
/theme solarized
```

The active theme is saved to `.collab/settings.toml` and restored on next launch.

## Configuration

Invalid values never silently loosen safety: a bad `claude_dangerously_skip_permissions` turns the bypass off, a malformed `dangerous_ops` uses the full default set, and every such problem is reported as a warning at launch and in the chat.

Settings live in `.collab/settings.toml` inside your repository. The file is created with defaults on first run. Edit it directly — changes take effect on the next launch.

```toml
[app]
# Session identity and default agent roles
identity = "codex"
role = "collaborator"
codex_role = "reviewer"
claude_role = "implementer"

# Maximum number of automatic agent relay turns before pausing for Master input
max_auto_turns = 12

# UI theme: akritrim | nord | dracula | solarized
theme = "akritrim"

# Model overrides — change to use a different model for either agent
claude_model = "claude-sonnet-5-5"
codex_model = "gpt-6-sol"

# Opt-in: run Codex in a read-only sandbox whenever its role is "reviewer".
# Codex cannot modify files, but review runs that write caches/temp files (e.g. pytest) may fail.
codex_reviewer_read_only = false

# Copy mouse-selected pane text to the clipboard as soon as the mouse is released.
copy_on_select = true

# Approval gate. "required" (default): Claude asks you BEFORE a dangerous command or CI-file edit runs, and a
# turn that cannot establish the gate does not run. "legacy": the older stop-and-resume check.
# Codex works the same way through `codex app-server` (writable turns only).
claude_approval_gate = "required"
codex_approval_gate = "required"

# Set to false to allow running outside a git repository.
# Codex will receive --skip-git-repo-check; diff display still works.
# Can also be overridden per run: --no-require-git
require_git = true

# Dangerous-operation gate.
# Agents must request Master approval before executing the listed operations.
# Stream-level interception aborts Claude's subprocess before the tool runs.
# Codex receives a post-execution warning (its event stream fires after execution).
#
# Set to an empty list to disable the gate entirely:
# dangerous_ops = []
#
# Or restrict to specific operations:
# dangerous_ops = ["git push", "npm publish", "rm -rf"]
#
# Omit the key to use the full default set (all operations listed above).

# TUI debug log — records lifecycle events, routing decisions, and stream activity.
# Useful for diagnosing unexpected routing or stuck sessions.
# The Claude stream JSONL log (one entry per turn) is always written to
# .collab/session/stream_debug.jsonl separately.
# debug_log = ".collab/session/tui_debug.log"
```

## Run Options

CLI flags override the corresponding `settings.toml` values for that run only:

```bash
akritrim-colab run --codex-role reviewer --claude-role implementer
akritrim-colab run --claude-model claude-opus-4-6
akritrim-colab run --no-require-git
akritrim-colab run --debug-log .collab/session/tui_debug.log
```

## Development

**Clone and install in editable mode:**

```bash
git clone https://github.com/akritrim/akritrim-colab
cd akritrim-colab
pip install -e ".[dev]"
```

Or with `uv`:

```bash
uv pip install -e ".[dev]"
```

**Run from source** (after editable install):

```bash
akritrim-colab
# or
python -m akritrim_colab
```

**Run the test suite:**

```bash
pytest
```

Tests use `pytest-asyncio` (auto mode). No live agent connections are required — the test suite mocks all CLI subprocess calls.

**Project layout:**

```
src/akritrim_colab/
  app.py                     Main TUI — CollabApp, all UI, routing, and relay logic
  cli.py                     Entry point — init / run subcommands, settings wiring
  config.py                  ProjectConfig, AppSettings, path resolution
  agents/
    claude_adapter.py        Claude CLI wrapper — streaming, session resume
    codex_adapter.py         Codex CLI wrapper — streaming, thread resume
    stream_events.py         StreamEvent dataclass shared by both adapters
tests/                       pytest test suite
.collab/                     Per-repo collaboration files (created on first run)
  memory.md                  Permanent decisions log
  scratchpad.md              Open topics and working notes
  rules.md                   Collaboration protocol rules
  settings.toml              User configuration
  session/                   Runtime state (gitignored)
```
