Two‑AI orchestrator (tmux) for evidence‑first, small‑step collaboration
Project description
CCCC Pair — Dual‑AI Orchestrator (Evidence‑first) · Agent‑as‑a‑Service (AaaS)
Two best‑in‑class AI CLIs (Claude Code + Codex CLI) co‑drive your work as equal peers. They collaborate, self‑review, and ship small, reversible changes with built‑in governance. You observe and nudge from tmux or IM. CCCC treats agents as long‑lived services — Agent‑as‑a‑Service (AaaS) — that speak the same contract, produce auditable evidence, and integrate with your team’s tools.
Not a chatbot UI. Not an IDE plugin. A production‑minded orchestrator for 24/7, long‑running work.
Why It’s Different
- Dual‑AI Autonomy: peers continuously plan → build → critique → refine. They don’t wait for prompts; they follow a mailbox contract and change the world only with EVIDENCE (diff/tests/logs/benchmarks).
- Agent‑as‑a‑Service (AaaS): agents are long‑running services with a mailbox contract, not ad‑hoc prompts. They keep rhythm, produce evidence, and integrate with IM (Telegram/Slack/Discord via bridges; Teams outbound planned) without coupling core logic to any single transport.
- IM Collaboration: a 24/7 agent lives in your team chat. High‑signal summaries, one‑tap RFD decisions, explicit routing (a:/b:/both:) so normal conversation remains normal. Files flow both ways with captions and sidecars.
- Builder–Critic Synergy: peers challenge CLAIMs with COUNTERs and converge via verifiable EVIDENCE. In practice this beats single‑model quality on complex, multi‑day tasks.
- tmux Transparency: dual panes (PeerA/PeerB) + compact status panel. You can peek, nudge, or inject text without disrupting flows—and without a GUI.
- Governance at the Core (RFD): protected areas and irreversible changes raise Request‑For‑Decision cards in chat; approvals are written to a ledger and unlock execution.
- Team‑level Efficiency: one always‑on bot concentrates orchestration and approvals for the whole team. You reduce duplicated “per‑seat” sessions and still retain control.
What You Get
- Evidence‑first loop: tiny diffs/tests/logs; only green changes commit.
- Single‑branch queue: preflight
git apply→ (optional) lint/tests → commit. - RFD closed loop: generate cards, gate protected paths/large diffs, unlock on decision.
- AaaS integration: explicit routing;
/status,/queue,/locks,/rfd list|show,/showpeers on|off, file send/receive with meta. Bridges mirror events; orchestrator remains transport‑agnostic. - Ledger: append‑only
.cccc/state/ledger.jsonl(patch/test/log/decision) for audit.
Requirements
- Python
>= 3.9 - tmux (e.g.,
brew install tmuxorsudo apt install tmux) - git (preflight/commits)
Supported CLIs (current)
- Peer A: Claude Code CLI (recommended: MAX Plan)
- Peer B: Codex CLI (recommended: PRO Plan)
Install
- Recommended (pipx)
pipx install cccc-pair
- Or venv
python3 -m venv v && . v/bin/activate && pip install cccc-pair
Quick Start (5 minutes)
- Initialize in your project repo
cccc init
This copies the scaffold to ./.cccc/ and appends /.cccc/** to .gitignore (Ephemeral).
- Check environment
cccc doctor
- (Optional) Enable Telegram
cccc token set # paste your bot token; stored in .cccc/settings/telegram.yaml (gitignored)
- Run orchestrator (tmux UI)
cccc run
tmux opens: left/right = PeerA/PeerB, bottom‑right = status panel. Run wizard (interactive TTY) lets you optionally connect a bridge:
-
- Local only (default)
-
- Local + Telegram
-
- Local + Slack
-
- Local + Discord
You can also manage bridges later via
cccc bridge …or setautostartin.cccc/settings/*.yaml.
- Local + Discord
You can also manage bridges later via
- First‑time CLI setup (required)
- Install the two CLIs and make sure the binaries are on PATH:
claude ...(Claude Code)codex ...(Codex CLI)
- Paste system prompts for best collaboration quality:
- Open
PEERA.mdand copy its full content into a new fileCLAUDE.mdat your repo root (not tracked;.gitignorealready ignores it). Claude Code CLI should load this as its system prompt. - Open
PEERB.mdand copy its full content into a new fileAGENTS.mdat your repo root (not tracked). Codex CLI should load this as its system prompt.
- Open
- Move any previous “project state” prompt into
PROJECT.mdat the repo root (recommended). The orchestrator will weave this into the runtime SYSTEM so both peers align on scope and goals. - Verify or adjust the CLI commands in
.cccc/settings/cli_profiles.yaml:commands.peerA: "claude ..."commands.peerB: "codex ..."- You can also override at runtime with env vars:
CLAUDE_I_CMD,CODEX_I_CMD.
First Landing Checklist (Minimal)
Do just these to get a clean, working setup:
cccc init(creates./.ccccand ignores runtime dirs)cccc doctor(git/tmux/python)- Prepare system prompts (required once per repo)
- Copy
PEERA.md→CLAUDE.md(root) - Copy
PEERB.md→AGENTS.md(root) - Put your brief/scope in
PROJECT.md(root)
- Copy
- Optional Telegram (highly recommended)
cccc token setcccc run(bridge autostarts) orcccc bridge start
- Start work:
cccc run(tmux panes + status panel)
That’s it. You can refine policies later.
IM Quickstart (Team Hub)
- Group routing: use explicit routes so normal chat stays normal
a: <text>/b: <text>/both: <text>- or
/a .../b .../both ...(works with privacy mode)
- Get oriented
/statusproject stats;/queuehandoff queue;/locksinternal locks/whoamishows your chat_id;/subscribe(ifautoregister: open)/showpeers on|offtoggles Peer↔Peer summaries
- File exchange
- Outbound (AIs → IM): save files to
.cccc/work/upload/outbound/(flat) - Routing: either a
<name>.routesidecar witha|b|both, or the first line of<name>.caption.txtstarts witha:/b:/both:(the prefix is removed from the caption) - ACK: on success, a
<name>.sent.jsonsidecar is written - Inbound (IM → AIs): bridge writes
<FROM_USER>with sidecar meta; peers act on it
- Outbound (AIs → IM): save files to
- Governance: RFD cards in chat with Approve/Reject; decisions go to the ledger and unlock execution.
A Typical Session (End‑to‑End, ~3 minutes)
Goal: ship a small, reversible change with dual‑AI collaboration.
- Explore (short)
- In Telegram (or tmux), route a brief idea to both:
both: Add a section to README about team chat tips - PeerA summarizes intent; PeerB asks 1 focused question if needed.
- Decide (concise CLAIM)
- PeerA writes a CLAIM in
peerA/to_peer.mdwith acceptance and constraints (≤150 lines; links to where to edit). - PeerB COUNTERs if there’s a sharper place or a safer rollout.
- Build (evidence‑first)
- PeerB produces a tiny unified diff in
peerB/patch.diff(e.g., add a new README subsection) and a 1–2 line EVIDENCE note (tests OK/lines/paths/MID). - Orchestrator preflights → applies → (optional) lint/tests → commits on green and logs to ledger.
- Team visibility
- Telegram posts a concise summary (debounced); peers stay quiet unless blocked.
- If you need files (screenshots/spec PDFs), drop them to the bot with a caption; peers act on the inbound block with meta.
RFD is not required here. It triggers automatically only for protected areas or when you explicitly ask for a decision.
Recommended Stack (Pragmatic & Stable)
- AI CLIs: Claude Code (MAX Plan) + Codex CLI (PRO Plan) for robust, sustained workloads.
- Orchestrator: this project, with tmux for long‑lived panes and a compact panel.
- Transport & Governance: Telegram for team‑wide visibility, quick RFD decisions, and file exchange.
Folder Layout (after cccc init)
.cccc/
adapters/bridge_telegram.py # Telegram long‑poll bridge (MVP)
adapters/bridge_slack.py # Slack bridge (Socket Mode + Web API, MVP)
adapters/bridge_discord.py # Discord bridge (Gateway + REST, MVP)
adapters/outbox_consumer.py # Shared Outbox reader (to_user/to_peer_summary)
settings/
cli_profiles.yaml # tmux/paste/type behavior; echo; idle regexes; self‑check
policies.yaml # patch queue size; allowlist; RFD gates
roles.yaml # leader; specialties; rotation
telegram.yaml # token/autostart/allowlist/routing/files
slack.yaml # app/bot tokens, channels, routing/files
discord.yaml # bot token, channels, routing/files
mailbox/ # peerA/peerB with to_user.md/to_peer.md/patch.diff; inbox/processed
work/ # shared workspace; upload inbound/outbound; ephemeral
state/ # ledger.jsonl, bridge logs, status/session; ephemeral
logs/ # extra logs; ephemeral
orchestrator_tmux.py delivery.py mailbox.py panel_status.py prompt_weaver.py
evidence_runner.py mock_agent.py
CLI Reference
cccc init [--force] [--to PATH]— copy scaffold; preserves layout; excludes runtime dirscccc doctor— check git/tmux/python/telegramcccc run— start orchestrator (tmux panes + status panel; optional bridge connect wizard; autostarts per YAML)cccc token set|unset|show— manage Telegram token (gitignored)cccc bridge <telegram|slack|discord|all> start|stop|status|restart|logs [-n N] [--follow]— control/inspect bridgescccc clean— purge.cccc/{mailbox,work,logs,state}/cccc version— show package version and scaffold path info
Adapter dependencies (optional)
- Slack bridge requires
slack_sdk(install viapip install slack_sdk). - Discord bridge requires
discord.py(install viapip install discord.py). If these packages or tokens are missing, adapters exit fast with a clear error. Slack inbound requires an App token (Socket Mode) while outbound requires a Bot token.
CLI prerequisites (summary)
- Peer A = Claude Code; Peer B = Codex CLI. Install and log in as required by each vendor.
- Ensure the binaries (
claude,codex) are on PATH or setcommands.peer*/CLAUDE_I_CMD/CODEX_I_CMD.
Key Configuration (snippets)
.cccc/settings/policies.yaml
patch_queue:
max_diff_lines: 150
allowed_paths: ["src/**","tests/**","docs/**","infra/**","README.md","PROJECT.md"]
rfd:
gates:
protected_paths: [".cccc/**","src/api/public/**"]
large_diff_requires_rfd: false
handoff_filter:
enabled: true
cooldown_seconds: 15
.cccc/settings/telegram.yaml
token_env: TELEGRAM_BOT_TOKEN
autostart: true
discover_allowlist: true
autoregister: open # open|off
allow_chats: [] # optional explicit allowlist (numeric chat IDs)
max_auto_subs: 3
show_peer_messages: true
default_route: both # a|b|both
# Message sizing and pacing
debounce_seconds: 30
max_msg_chars: 4096
max_msg_lines: 32
peer_debounce_seconds: 30
peer_message_max_chars: 4096
peer_message_max_lines: 32
routing:
require_explicit: true # require a:/b:/both: (groups)
allow_prefix: true # allow a:/b:/both: prefixes
require_mention: false # require @BotName in groups (false = more convenient)
dm:
route_default: both # default when in DM
hints:
cooldown_seconds: 300
files:
enabled: true
max_mb: 16
allowed_mime: ["text/*","image/png","image/jpeg","application/pdf","application/zip"]
inbound_dir: .cccc/work/upload/inbound
outbound_dir: .cccc/work/upload/outbound
inbound_retention_days: 14
outbound_retention_days: 14
autowrap_from_user: true
run_clamav: false
redact_patterns:
- (?i)api[_-]?key\s*[:=]\s*\S+
- (?i)secret\s*[:=]\s*\S+
- (?i)password\s*[:=]\s*\S+
outbound:
reset_on_start: clear
.cccc/settings/slack.yaml
# Tokens
app_token_env: SLACK_APP_TOKEN # xapp-... for Socket Mode (optional inbound)
bot_token_env: SLACK_BOT_TOKEN # xoxb-... for Web API (required)
# Routing & display
show_peer_messages: true
default_route: both # a|b|both when no explicit prefix
# Channels (channel IDs)
channels:
to_user: []
to_peer_summary: []
# Outbound
outbound:
reset_on_start: clear # baseline|clear
# Files
files:
enabled: true
max_mb: 16
inbound_dir: .cccc/work/upload/inbound
outbound_dir: .cccc/work/upload/outbound
.cccc/settings/discord.yaml
# Token
bot_token_env: DISCORD_BOT_TOKEN
# Routing & display
show_peer_messages: true
default_route: both # a|b|both when no explicit prefix
# Channels (numeric IDs)
channels:
to_user: []
to_peer_summary: []
# Outbound
outbound:
reset_on_start: clear # baseline|clear
# Files
files:
enabled: true
max_mb: 16
inbound_dir: .cccc/work/upload/inbound
outbound_dir: .cccc/work/upload/outbound
Feature Overview (selected)
- Bridges: Telegram (inbound/outbound), Slack (Socket Mode + Web API, MVP), Discord (Gateway + REST, MVP). Outbound reads single‑source Outbox (
.cccc/state/outbox.jsonl) via a shared consumer; inbound routesa:/b:/both:to mailbox inbox. No dry‑run: tokens/SDKs are required and adapters fail fast when missing. - Unified bridge CLI:
cccc bridge <telegram|slack|discord|all> start|stop|status|restart|logsand an optional connect wizard incccc run. Bridges can autostart via YAML. - Context maintenance: on a cadence (config
delivery.context_compact_every_self_checks), send/compactto both CLIs and immediately reinject the full SYSTEM with a leading “Now: … TZ” line. - Self‑check enhancements: inject current time/TZ; add an insight‑channel reminder to generate new angles (hook/assumption/risk/trade‑off/next/delta) rather than restating.
- NUDGE improvements: exponential backoff, jitter, progress timeout; guidance for productive action when inbox is empty.
- REV gate: after a COUNTER/QUESTION, the next to_peer must be a valid revise (insight.kind=revise with delta/refs/next and not restating) or carry direct evidence (inline unified diff). Otherwise the message is intercepted with a short tip and logged.
FAQ / Troubleshooting
tmux panes not appearing?
- Install tmux (
tmux -V), run in a TTY, thencccc run. Checkcccc doctor.
Telegram bot silent?
cccc token show(token saved?) →cccc bridge status(running?) →cccc bridge logs -n 200- In group chats, route explicitly (
a://a), and run/whoamior/subscribeonce to register - Ensure
autostart: true
Claude/Codex CLI not found?
- Install the CLIs and make sure the binaries are on PATH; otherwise set explicit commands:
- Edit
.cccc/settings/cli_profiles.yaml(commands.peerA|peerB) or - Export env vars before
cccc run:CLAUDE_I_CMD="/path/to/claude ...",CODEX_I_CMD="/path/to/codex ..."
- Edit
Where to put my project brief/policies?
- Put your project scope/brief in
PROJECT.md(repo root). The orchestrator injects it into the runtime SYSTEM so both peers align. - RFD/protected paths live in
.cccc/settings/policies.yaml.
“This environment is externally managed” during install/build?
- Use a venv or pipx for publishing; avoid system Python for
pip installof tools like build/twine.
RFD card not shown?
- Confirm ledger has
kind:rfd; check bridge logs; verify gates and to_peer YAML format.
Security & Privacy
- Telegram token saved to
.cccc/settings/telegram.yaml(gitignored) or env; do not commit secrets. - Bridge redacts common secret patterns; keep mailbox content free of tokens.
- Orchestrator domain
.cccc/**is runtime; do not commitstate/logs/work/mailbox.
Roadmap (Selected)
- Role‑based approvals; multi‑sign gates; richer RFD templates with default options/expiry
- Artifact previews in chat; repro snippets; CI/CD hooks for release/rollback cards
- Optional safety scanners (ClamAV/DLP) for inbound files; Slack/Mattermost bridges
License
Apache (see LICENSE).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cccc_pair-0.2.9.tar.gz.
File metadata
- Download URL: cccc_pair-0.2.9.tar.gz
- Upload date:
- Size: 195.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1c72ba700f4a6e99a6607d86163b5ffeeb32e81c8e4ad98c8cb7e00db3ca73ed
|
|
| MD5 |
3816c398d1e17f4975c3251cbebb57b3
|
|
| BLAKE2b-256 |
d16eb738ccf2c18a0cdb396bbf53f4f1c6a1c8b3788f1a851ee804254892b182
|
File details
Details for the file cccc_pair-0.2.9-py3-none-any.whl.
File metadata
- Download URL: cccc_pair-0.2.9-py3-none-any.whl
- Upload date:
- Size: 210.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f03c1544c68aebf61be5ea0acc94baad28c24310bffb55bafb5e73f8a0cd9267
|
|
| MD5 |
16a1c8a63fb133dec801b6590d5ba080
|
|
| BLAKE2b-256 |
3cc4515a1fa638e418e7b8bd75538876feadac8e5648f403a997b193a8a32352
|