{"id":50477592,"url":"https://github.com/jkirsteins/workbridge","last_synced_at":"2026-06-01T14:31:31.913Z","repository":{"id":352255248,"uuid":"1199921749","full_name":"jkirsteins/workbridge","owner":"jkirsteins","description":"Multi-repo coding agent orchestration in your terminal.","archived":false,"fork":false,"pushed_at":"2026-04-18T16:56:13.000Z","size":2029,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-04-18T18:15:57.957Z","etag":null,"topics":["agent-orchestration","claude-code","codex","coding-agent","developer-tools","git-worktree","ratatui","rust","terminal-ui","tui"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jkirsteins.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-02T21:10:33.000Z","updated_at":"2026-04-18T17:07:52.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jkirsteins/workbridge","commit_stats":null,"previous_names":["jkirsteins/workbridge"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/jkirsteins/workbridge","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkirsteins%2Fworkbridge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkirsteins%2Fworkbridge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkirsteins%2Fworkbridge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkirsteins%2Fworkbridge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jkirsteins","download_url":"https://codeload.github.com/jkirsteins/workbridge/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkirsteins%2Fworkbridge/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33780086,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-01T02:00:06.963Z","response_time":115,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-orchestration","claude-code","codex","coding-agent","developer-tools","git-worktree","ratatui","rust","terminal-ui","tui"],"created_at":"2026-06-01T14:31:30.931Z","updated_at":"2026-06-01T14:31:31.895Z","avatar_url":"https://github.com/jkirsteins.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"assets/logo.png\" alt=\"Workbridge logo\" width=\"180\" /\u003e\n  \u003ch1\u003eWorkbridge\u003c/h1\u003e\n  \u003cp\u003e\u003cstrong\u003eMulti-repo coding agent orchestration in your terminal.\u003c/strong\u003e\u003c/p\u003e\n\u003c/div\u003e\n\nWorkbridge is a terminal UI for orchestrating multi-repo development work. It\ntracks work items, manages git worktrees, and drives coding agent sessions\nthrough a Backlog -\u003e Planning -\u003e Implementing -\u003e Review -\u003e Done workflow.\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"assets/screenshot.png\" alt=\"Workbridge TUI screenshot\" width=\"800\" /\u003e\n\u003c/div\u003e\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n  - [1. Build and install Workbridge](#1-build-and-install-workbridge)\n  - [2. Register the repos you want to manage](#2-register-the-repos-you-want-to-manage)\n  - [3. Launch the TUI](#3-launch-the-tui)\n  - [4. Start your first quick-start session](#4-start-your-first-quick-start-session)\n- [How It Works](#how-it-works)\n  - [Work Item Lifecycle](#work-item-lifecycle)\n  - [Global assistant drawer](#global-assistant-drawer)\n  - [MCP Communication](#mcp-communication)\n  - [Module architecture](#module-architecture)\n- [Compatibility](#compatibility)\n- [Per-harness permission model](#per-harness-permission-model)\n- [Further Reading](#further-reading)\n- [License](#license)\n\n## Quick Start\n\n### 1. Build and install Workbridge\n\nWorkbridge is distributed as a Rust binary crate:\n\n```sh\ncargo install workbridge\n```\n\nFor local development from a checkout, install the current workspace instead:\n\n```sh\ncargo install --path .\n```\n\nFor local development without installing, `cargo run -- \u003cargs\u003e` works the same\nway as the installed `workbridge` binary.\n\n### 2. Register the repos you want to manage\n\nWorkbridge does not walk your filesystem. You tell it which repos to scan,\neither one at a time or by registering a base directory that gets scanned one\nlevel deep:\n\n```sh\nworkbridge repos add .                  # register the current repo\nworkbridge repos add ~/Projects/foo     # register a specific repo\nworkbridge repos add-base ~/Projects    # discover repos under ~/Projects\n```\n\nRepos added with `repos add` are always active. Repos discovered under a base\ndirectory start unmanaged - opt them in from the TUI settings overlay (`?`)\nor with an explicit `repos add`. See [docs/repository-registry.md](docs/repository-registry.md)\nfor the full CLI reference and config file format.\n\n### 3. Launch the TUI\n\n```sh\nworkbridge\n```\n\nThe left panel lists work items grouped by status. Press `?` at any time to\nopen the settings overlay (config path, base dirs, managed/available repos,\ndefaults).\n\nBefore starting work, open the **Review Gate** tab in the settings overlay\n(`?`, then Tab to reach the Review Gate tab) and set the \"Skill (slash\ncommand)\" field. The value is passed verbatim to whichever coding agent runs\nthe review gate, so it can be a slash command (e.g.\n`/claude-adversarial-review` for Claude Code) or plain-text guidance that any\ncoding agent can follow. The default is a Claude Code slash command - update\nit if you are using a different coding agent.\n\n### 4. Start your first quick-start session\n\nPress `Ctrl+N` to begin a quick-start session. If you have exactly one managed\nrepo, Workbridge skips the dialog and creates a Planning work item immediately\nwith a placeholder title; otherwise a compact \"Quick start - select repo\"\ndialog appears so you can pick the repo with Up/Down + Space, then Enter.\n\nThe coding agent session that spawns will ask what you want to work on, set a\nreal title via MCP, and walk through planning. When planning is done it records the\nplan and the item is ready to advance to Implementing. See\n[docs/work-items.md](docs/work-items.md) for the full lifecycle, including\nthe review and merge gates.\n\n`Ctrl+B` opens the full creation dialog (title, description, repos, branch)\nif you want to create a Backlog item instead of jumping straight into\nplanning.\n\n## How It Works\n\nWork items are Workbridge's central abstraction. Each one owns a branch, a\nworktree, an optional GitHub issue, and an optional PR, and moves through a\nlinear sequence of stages driven by coding agent sessions. Two gates protect\nthe flow: the **review gate** (PR exists, CI is green, adversarial code\nreview passes the plan-vs-implementation check) and the **merge gate** (the\nPR is actually merged on GitHub).\n\n### Work Item Lifecycle\n\n```mermaid\nflowchart TD\n    QS[\"Ctrl+N\u003cbr/\u003equick start\"] --\u003e Planning\n    CD[\"Ctrl+B\u003cbr/\u003ecreation dialog\"] --\u003e Backlog\n    GA[\"Global assistant\u003cbr/\u003etransfer\"] --\u003e Planning\n    RR[\"Review requested\u003cbr/\u003eon your PR\"] --\u003e Review\n\n    Backlog --\u003e Planning\n    Planning --\u003e|plan recorded| Implementing\n    Implementing \u003c--\u003e|stuck / unblocked| Blocked\n    Implementing --\u003e|review gate| Review\n    Blocked --\u003e|review gate| Review\n    Review --\u003e|merge gate| Done\n    Review \u003c--\u003e|poll strategy / retreat| Mergequeue\n    Mergequeue --\u003e|PR merged externally| Done\n```\n\nSee [docs/work-items.md](docs/work-items.md) for the full stage semantics,\ngate behavior, and review-request workflow.\n\n### Global assistant drawer\n\nPress `Ctrl+G` at any time to open the global assistant drawer. Unlike a\nwork item session, the global assistant has read-only access to all your\nmanaged repos and work items, and can create new work items on your behalf\nvia the `workbridge_create_work_item` MCP tool. Use it to explore across\nrepos, ask \"what is in flight right now\", or kick off a Planning work item\nfrom a freeform conversation - that last path is what the lifecycle\ndiagram above shows as the `Global assistant transfer -\u003e Planning` edge.\n\n### MCP Communication\n\nWorkbridge talks to each harness session over a per-session Unix domain\nsocket. The harness binary is `claude` or `codex`, picked per work item\nvia the `c` / `x` keys (see\n[docs/harness-contract.md](docs/harness-contract.md)); the MCP tool\nsurface is the same for both adapters, only the spawn-side flag syntax\ndiffers (`--mcp-config \u003cfile\u003e` for Claude, `-c mcp_servers.\u003cname\u003e.*`\nTOML overrides for Codex). When a session is spawned - work item\nplanning, implementing, review-request handling, the headless review or\nrebase gate, or the global assistant drawer - Workbridge starts a small\nMCP server on a fresh socket and configures the harness to spawn\n`workbridge --mcp-bridge --socket \u003cpath\u003e` as its MCP server. The bridge\nsubprocess pipes stdin/stdout to the socket so the harness's JSON-RPC\ntool calls reach the in-process server.\n\nEach session is handed a context blob at spawn time: a frozen snapshot\nfor work-item sessions, and an `Arc\u003cMutex\u003cString\u003e\u003e` that the TUI\nrefreshes periodically for the global assistant. State-mutating tool\ncalls become `McpEvent`s on a crossbeam channel that the TUI applies on\nits main thread; read-only tool calls are served directly by the MCP\nserver from that context (or, for `workbridge_query_log`, from the\non-disk activity log) without round-tripping through the TUI.\n\n```mermaid\nflowchart LR\n    subgraph TUI[\"Workbridge TUI (main thread)\"]\n        State[\"Work item state\u003cbr/\u003e(stage, plan, title, activity)\"]\n        Drawer[\"Global assistant drawer\u003cbr/\u003e(Ctrl+G)\"]\n    end\n\n    subgraph Spawn[\"Spawn paths (App spawn_* methods)\"]\n        SS[\"spawn_session\u003cbr/\u003eplanning / implementing /\u003cbr/\u003ereview request\"]\n        SR[\"spawn_review_gate (read_only=true)\u003cbr/\u003espawn_rebase_gate (read_only=false)\"]\n        SG[\"spawn_global_session\"]\n    end\n\n    subgraph Sessions[\"Harness sessions\u003cbr/\u003e(claude or codex)\"]\n        WiSession[\"Work item session\"]\n        GateSession[\"Headless gate session\"]\n        GaSession[\"Global assistant session\"]\n    end\n\n    subgraph Mcp[\"MCP server (crate::mcp module)\"]\n        WiSock[\"Per-work-item socket\"]\n        GaSock[\"Global socket\"]\n    end\n\n    State -- \"context snapshot\" --\u003e SS\n    State -- \"context snapshot\" --\u003e SR\n    Drawer -- \"refreshable context\" --\u003e SG\n    SS --\u003e WiSession\n    SR --\u003e GateSession\n    SG --\u003e GaSession\n\n    WiSession -- \"JSON-RPC tool calls\" --\u003e WiSock\n    GateSession -- \"JSON-RPC tool calls\" --\u003e WiSock\n    GaSession -- \"JSON-RPC tool calls\" --\u003e GaSock\n\n    WiSock -- \"state-mutating tool calls\u003cbr/\u003ebecome McpEvents\" --\u003e State\n    GaSock -- \"workbridge_create_work_item\u003cbr/\u003ebecomes an McpEvent\" --\u003e State\n```\n\nPer-session tool surface (see the `crate::mcp` module for the source of truth):\n\n- **Interactive work-item session** and **rebase gate**: read-only\n  `workbridge_get_context`, `workbridge_query_log`; mutating\n  `workbridge_log_event`, `workbridge_set_activity`,\n  `workbridge_delete`, `workbridge_set_status`, `workbridge_set_plan`,\n  `workbridge_set_title`. The rebase gate is spawned with\n  `read_only=false` and gets the same mutating set as the interactive\n  session - it has to call `workbridge_log_event` to stream live\n  rebase progress back to the TUI.\n- **Review-request work-item session**: same read-only tools plus\n  `workbridge_log_event`, `workbridge_set_activity`, and\n  `workbridge_delete`; `set_status` / `set_plan` / `set_title` are\n  replaced by `workbridge_approve_review` and\n  `workbridge_request_changes`.\n- **Review gate** (headless, `read_only=true`):\n  `workbridge_get_context`, `workbridge_query_log`,\n  `workbridge_get_plan`, `workbridge_report_progress`. Mutating tools\n  are not exposed in `tools/list` and are rejected at `tools/call`\n  even if the harness asks for them by name.\n- **Global assistant session** (separate socket, separate handler):\n  read-only `workbridge_list_repos`, `workbridge_list_work_items`,\n  `workbridge_repo_info`; mutating `workbridge_create_work_item`,\n  which spawns a new Planning work item.\n\n### Module architecture\n\nThe workbridge binary is organized as a single crate with one module\nper subsystem. The TUI runs on a single main thread that owns the\n`App` aggregate; every blocking operation (git, `gh`, PTY I/O, metrics\naggregation) is spawned onto a background thread and drains back\nthrough a crossbeam or `mpsc` channel. Host-visible APIs (clipboard,\nwall-clock time, user directories) are routed through a gated\n`side_effects` module so the test suite cannot touch the developer's\nreal environment.\n\n```mermaid\nflowchart LR\n    classDef entry fill:#dbeafe,stroke:#2563eb,color:#0f172a\n    classDef ui fill:#ede9fe,stroke:#7c3aed,color:#0f172a\n    classDef core fill:#fef3c7,stroke:#d97706,color:#0f172a\n    classDef svc fill:#dcfce7,stroke:#16a34a,color:#0f172a\n    classDef bg fill:#fee2e2,stroke:#dc2626,color:#0f172a\n    classDef gate fill:#f1f5f9,stroke:#475569,color:#0f172a\n\n    Main[\"main\u003cbr/\u003ebinary entry + handle_cli\"]:::entry\n    CLI[\"cli::{repos, mcp,\u003cbr/\u003econfig, seed_dashboard}\"]:::entry\n\n    Salsa[\"salsa\u003cbr/\u003erat-salsa event loop\"]:::ui\n    App[\"app::App\u003cbr/\u003eaggregate state\"]:::ui\n    UI[\"ui\u003cbr/\u003erender functions\"]:::ui\n    Event[\"event::{keyboard,\u003cbr/\u003emouse, paste, layout}\"]:::ui\n\n    Assembly[\"assembly\u003cbr/\u003ereassemble work items\"]:::core\n    CreateDialog[\"create_dialog\u003cbr/\u003eCreateDialog, SetBranchDialog\"]:::core\n    Session[\"session\u003cbr/\u003ePTY session lifecycle\"]:::core\n    WorkItem[\"work_item\u003cbr/\u003eWorkItem types + enums\"]:::core\n\n    AgentBackend[\"agent_backend\u003cbr/\u003eAgentBackend trait +\u003cbr/\u003eclaude_code / codex / opencode\"]:::svc\n    WorkItemBackend[\"work_item_backend\u003cbr/\u003eWorkItemBackend trait +\u003cbr/\u003elocal_file / mock\"]:::svc\n    WorktreeService[\"worktree_service\u003cbr/\u003eWorktreeService trait +\u003cbr/\u003egit_impl\"]:::svc\n    GithubClient[\"github_client\u003cbr/\u003eGithubClient trait +\u003cbr/\u003ereal (gh) / stub / mock\"]:::svc\n    Config[\"config\u003cbr/\u003eConfig, FileConfigProvider,\u003cbr/\u003eloader, operations\"]:::svc\n    Mcp[\"mcp\u003cbr/\u003eMcpSocketServer, server,\u003cbr/\u003ebridge\"]:::svc\n\n    Fetcher[\"fetcher\u003cbr/\u003eper-repo poller threads\"]:::bg\n    Metrics[\"metrics\u003cbr/\u003edashboard aggregator\"]:::bg\n\n    SideEffects[\"side_effects\u003cbr/\u003eclipboard, clock, paths\u003cbr/\u003e(#[cfg(not(test))] gate)\"]:::gate\n\n    Main --\u003e CLI\n    Main --\u003e Salsa\n    CLI --\u003e Config\n    Salsa --\u003e App\n    Salsa --\u003e UI\n    Salsa --\u003e Event\n\n    Event --\u003e App\n    UI --\u003e App\n    App --\u003e Assembly\n    App --\u003e CreateDialog\n    App --\u003e Session\n    App --\u003e WorkItem\n\n    Assembly --\u003e WorkItem\n    Assembly --\u003e WorkItemBackend\n    App --\u003e AgentBackend\n    App --\u003e WorkItemBackend\n    App --\u003e WorktreeService\n    App --\u003e GithubClient\n    App --\u003e Config\n    App --\u003e Mcp\n    App --\u003e Fetcher\n    App --\u003e Metrics\n\n    Session --\u003e AgentBackend\n    Session --\u003e Mcp\n\n    Fetcher --\u003e WorktreeService\n    Fetcher --\u003e GithubClient\n\n    Metrics --\u003e WorkItemBackend\n\n    WorktreeService --\u003e SideEffects\n    GithubClient --\u003e SideEffects\n    WorkItemBackend --\u003e SideEffects\n    Config --\u003e SideEffects\n    Metrics --\u003e SideEffects\n```\n\n- **Entry and CLI (blue):** `main` parses argv, dispatches to the\n  appropriate `cli::*::handle_*_subcommand`, or falls through to the\n  TUI path.\n- **UI layer (purple):** `salsa` wires rat-salsa to the `App`\n  aggregate; `ui` owns pure render functions; `event` routes\n  keyboard, mouse, paste, and resize events back to `App`.\n- **Core (amber):** `assembly` merges persisted records with live\n  fetcher data into `WorkItem` values; `create_dialog` owns the\n  creation-modal and set-branch-modal state; `session` drives PTY\n  lifecycle for spawned harnesses.\n- **Services (green):** every external dependency is a trait with a\n  real implementation and a stub/mock. `agent_backend` isolates\n  harness CLI differences; `work_item_backend` persists records;\n  `worktree_service` wraps `git`; `github_client` wraps `gh`;\n  `config` loads `config.toml`; `mcp` serves per-session JSON-RPC\n  over a Unix socket.\n- **Background workers (red):** `fetcher` runs one polling thread\n  per registered repo and streams results via `mpsc`; `metrics` runs\n  a single aggregator thread and streams snapshots via\n  `crossbeam-channel`.\n- **Side-effects gate (slate):** every clipboard / clock / user-dirs\n  call routes through `side_effects::*`, which returns no-ops under\n  `#[cfg(test)]` so the test suite cannot write the developer's real\n  clipboard, read the system clock, or touch `$HOME`.\n\n## Compatibility\n\nWorkbridge is harness-agnostic. Any CLI that satisfies the clauses in\n[`docs/harness-contract.md`](docs/harness-contract.md) can be plugged in. Today\nthe shipping adapters are:\n\n- **Claude Code** - reference adapter. Drives every workflow stage including\n  the headless review gate.\n- **Codex** - first-class secondary adapter. Drives every workflow stage.\n  Uses a handful of CLI-level workarounds for features that Codex does not\n  expose directly (see footnotes below and the per-clause notes in\n  `docs/harness-contract.md`).\n- **opencode** - planned. The adapter enum has a stub variant; the harness\n  is not yet selectable from the picker.\n\nPick the harness per work item with `c` (Claude Code) / `x` (Codex) in the\nwork item list; the right-panel session tab title reflects the harness\nactually running in the live session.\n\n### Feature matrix\n\nUser-observable features, per harness. \"Partial\" means the feature works end\nto end but via a different mechanism than Claude Code, and may differ in\ngranularity. See `docs/harness-contract.md` for the authoritative technical\ncontract.\n\n| Feature                                        | Claude Code | Codex     | opencode |\n| ---------------------------------------------- | :---------: | :-------: | :------: |\n| Planning sessions (interactive PTY)            | Yes         | Yes       | Planned  |\n| Implementing / Blocked sessions (interactive)  | Yes         | Yes       | Planned  |\n| Review sessions (interactive)                  | Yes         | Yes       | Planned  |\n| Review gate (headless, structured output)      | Yes         | Yes       | Planned  |\n| Global assistant (`Ctrl+G`)                    | Yes         | Yes       | Planned  |\n| Workbridge MCP server injection                | Yes         | Partial*  | Planned  |\n| CLI-level tool allowlist                       | Yes         | Partial** | Planned  |\n| Stage reminders (periodic nudges)              | Yes         | Partial***| Planned  |\n| Fresh-session-per-stage invariant              | Yes         | Yes       | Planned  |\n\n\\* Claude Code accepts a single `--mcp-config \u003cfile\u003e` JSON blob; Codex reads\nits MCP servers from `~/.codex/config.toml` and is fed via per-field `-c\nmcp_servers.workbridge.*=...` overrides instead. Functionally equivalent from\nthe user's perspective; see `docs/harness-contract.md` C4.\n\n\\** Claude Code enforces the workbridge tool allowlist via `--allowedTools`\nat the CLI; Codex does not expose an equivalent flag, so tool gating relies\non the workbridge MCP server filter. Same effective result for the\nread-only review gate; interactive work-item sessions see a broader tool\nsurface with Codex. See `docs/harness-contract.md` C5.\n\n\\*** Claude Code uses a `PostToolUse` hook to inject periodic stage\nreminders; Codex has no matching hook, so the Planning reminder is embedded\nin the system prompt and fires only at spawn, not on each turn. This is\nstrictly weaker than the hook-based delivery because it cannot re-fire after\nthe first turn. See `docs/harness-contract.md` C8.\n\n## Per-harness permission model\n\nWorkbridge runs LLM coding CLIs in your terminal. Each harness has its own\npermission model; workbridge's defaults differ per harness, summarised here:\n\n| Harness     | In-CLI approval prompts | Filesystem sandbox | Network access | How it's enforced |\n|-------------|-------------------------|--------------------|----------------|-------------------|\n| Claude Code | Bypassed (`--dangerously-skip-permissions`) | None - Claude has no built-in sandbox | Unrestricted | workbridge MCP server allowlist (`--allowedTools`); per-stage system prompt |\n| Codex       | Bypassed (`--dangerously-bypass-approvals-and-sandbox`) | None | Unrestricted | workbridge MCP server allowlist; per-server `default_tools_approval_mode = \"approve\"` |\n\nBoth harnesses run with full filesystem and network access - workbridge spawns\nthem on the same trust footing as running them yourself in a shell. The `[!]`\nmarker next to a session's harness name in the right-panel tab title is a\nvisible reminder of this.\n\n### Why Codex doesn't use its built-in sandbox\n\nworkbridge runs each work item in a linked git worktree at\n`\u003crepo\u003e/.worktrees/\u003cslug\u003e/`. Git stores that worktree's index outside the\nworktree, at `\u003crepo\u003e/.git/worktrees/\u003cslug\u003e/`. Codex's default `workspace-write`\nsandbox forbids writes outside the cwd, so `git commit` inside the worktree\nfails: git tries to create `\u003crepo\u003e/.git/worktrees/\u003cslug\u003e/index.lock` and the\nsandbox returns `Operation not permitted`.\n\nGranting `\u003crepo\u003e/.git/` as a writable root does not work either - Codex's\nprotected-paths rule denies writes to any `.git/` directory recursively.\nGranting individual subpaths (`objects/`, `refs/`, `logs/`, ...) papers over\n`git commit` but still produces `packed-refs.lock` denials, blocks `git push`\n(network is also off by default in workspace-write), and breaks `cargo build`\nagainst `~/.cargo/registry/`. Rather than maintain a fragile, ever-growing\nlist of writable_roots that approximates \"everything except `~/.ssh`\",\nworkbridge runs Codex without the built-in sandbox.\n\n## Further Reading\n\n- [CONTRIBUTING.md](CONTRIBUTING.md) - coding standards, error handling, UI rules\n- [RELEASING.md](RELEASING.md) - cutting a new release (cargo-release workflow)\n- [docs/cli.md](docs/cli.md) - full CLI reference for every `workbridge` subcommand and flag\n- [docs/repository-registry.md](docs/repository-registry.md) - repo registration and config\n- [docs/work-items.md](docs/work-items.md) - work item lifecycle and stages\n- [docs/UI.md](docs/UI.md) - TUI layout and interactions\n- [docs/invariants.md](docs/invariants.md) - project invariants (read-only)\n\n## License\n\nWorkbridge is released under the MIT License. See [LICENSE](LICENSE) for the\nfull text.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjkirsteins%2Fworkbridge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjkirsteins%2Fworkbridge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjkirsteins%2Fworkbridge/lists"}