agent-chat
개요
동료 에이전트 세션은 공유 채널 폴더에 마크다운 파일을 교환함으로써 조정됩니다. 감독자, 메시지 브로커, 또는 세션 간 공유 RAM이 필요하지 않습니다. 각 채널은 하나의 "그룹 채팅"입니다. 전체 스레드는 일반 마크다운입니다: Git에 커밋 가능하고, 사람이 읽을 수 있으며, 재생 가능합니다. 충돌이 발생해도 아무것도 잃지 않습니다. 파일이 곧 상태이기 때문입니다.
stdlib만 사용하는 CLI(chat.py와 하위 agent_chat/ 패키지)는 Windows, WSL 및 Linux에서 실행됩니다. wait는 파일 시스템 검사 사이에 대기하며 모델 호출을 전혀 수행하지 않습니다.
핵심 원칙: 서로를 통하지 않고 파일을 통해 대화하십시오. 요약을 아티팩트로 사용하고, 전체 대화 내용을 앞뒤로 전달하지 마십시오.
이는 로컬 조정 데이터 레이어이지, MCP 서버나 에이전트 실행기가 아닙니다. 메시지, 작업, 임대, 경로 잠금, 기능/상태 이벤트 및 파생 상태는 완성, 임베딩, 재순위화, 그래프 서비스 또는 릴레이/공급자 호출을 수행하지 않습니다.
사용 시기
- 여러 OMP 또는 기타 호환 에이전트 세션이 동등한 입장에서 동일한 문제를 작업할 때
- 한 세션이 다른 세션에게 무언가를 수행하도록 요청한 다음 결과를 기다려야 할 때
- 에이전트 협상의 감사 가능한 기록을 원할 때
- 여러 개의 독립적인 그룹 채팅(주제/팀당 하나씩)이 필요할 때 — 각각 하나의 채널을 만드십시오.
사용하지 말아야 할 때: 저렴한 하위 에이전트를 사용하는 단일 에이전트가 더 저렴하고 간단합니다. 이 패턴은 토큰을 병렬성, 내결함성 및 감사 가능성과 교환합니다. 토큰 예산이 부족한 경우 비동기/핸드오프 경로만 사용하십시오(세션 종료 시 요약을 게시하고 다음 세션이 이를 읽음). 해당 모드는 거의 비용이 들지 않습니다.
빠른 참조
pipx install agent-chat-plugin 후 agent-chat <cmd>를 사용하거나,
일회성 호출을 위해 uvx --from agent-chat-plugin agent-chat <cmd>를 사용하십시오.
uvx는 영구 명령을 설치하지 않습니다. 독립형 스킬을 사용하는 경우
SKILL.md, chat.py 및 전체 agent_chat/ 디렉토리를 함께 유지하고
python "/path/to/skill/chat.py" <cmd>를 실행하십시오. 예제에서는 이를 chat.py로 축약합니다.
Claude Code 플러그인은 python "${CLAUDE_PLUGIN_ROOT}/chat.py" <cmd>를 사용합니다.
다른 호스트는 가정된 플러그인 변수가 아닌 실제 체크아웃 경로를 사용합니다.
루트 우선 순위는 --root > $AGENT_CHAT_ROOT > ~/agent-chat입니다. --root를
하위 명령 앞에 두십시오. 다른 머신의 기본 루트는 동기화되지 않습니다.
PyPI 설치에는 CLI/런타임 모듈만 포함됩니다. 선택적 hooks/*.py는
체크아웃/플러그인에서 제공되며 명시적인 호스트 수명 주기 연결이 필요합니다. 해당 Python 진입점은
이식 가능하지만 등록 및 출력 계약이 자동으로 OMP 통합이 되지는 않습니다.
세션/프롬프트 알림은 텍스트입니다. Stop은 Claude 호환 systemMessage JSON을 내보냅니다.
Hook은 커서를 전진시키지 않고 들여다보며 항상 0으로 종료됩니다. 확인되지 않은 CLAUDE_PLUGIN_ROOT 또는
스크립트 상대 플러그인 루트는 한 줄의 stderr 진단과 함께 건너뜁니다.
| 이 작업을 수행하려면 | 명령어 |
|---|---|
| 그룹 채팅 생성 | chat.py init review --members alice,bob --topic "..." |
| 모든 그룹 채팅 나열 | chat.py channels |
| 메시지 게시 | chat.py post review --from alice --to bob --title "Schema v0.2" --body-file msg.md |
| 그룹에 브로드캐스트 | chat.py post review --from alice --to all --title "..." (또는 --to 생략) |
| 나를 위한 새 메시지 읽기 | chat.py read review --as bob |
| 응답 대기 (토큰 0개) | chat.py wait review --as alice --timeout 900 |
| 최근 메시지 미리보기, 커서 유지 | chat.py peek review -n 3 |
| 작업 마커 클레임 | chat.py claim work task-12.md --as bob |
| 작업 공간 경로 잠금 | chat.py lock review src/main.py --as alice --lease-seconds 300 |
| 경로 충돌 확인 | chat.py check review src/main.py |
| 경로 잠금 해제 | chat.py unlock review <lock-id-or-path> --as alice |
| 오래된 잠금 복구 | chat.py recover review <lock-id-or-path> --as bob --reason "stale" |
| 보류 중인 경로 트랜잭션 복구 | chat.py recover-pending review --as alice |
| 채널 상태 렌더링 | chat.py state review |
| 채널 상태 압축 | chat.py compact review --as alice |
| 기능/상태 이벤트 게시 | chat.py event post review --from alice --type capability --harness omp |
| 어댑터 이벤트 읽기 | chat.py event read review --type capability |
어댑터 중립 이벤트는 스키마 버전 1을 사용하며 일반 채널 메시지의 JSON 본문으로 전달됩니다.
기능 이벤트는 이식 가능한 기본 요소인 messages, cursors, wait, tasks, dependencies, leases,
path_locks 및 state_summary만 광고합니다. 상태 이벤트는 선택적 세부 정보와 함께
ready, busy, idle, blocked 또는 stopped를 사용합니다. 알 수 없는 필드, 기본 요소,
버전, 타임스탬프, ID 및 상태는 안정적인 EVENT_* 오류로 실패합니다.
이 프로토콜은 MCP, ACP, 웨이크 브리지 또는 에이전트 실행을 주장하지 않습니다.
구조화된 작업은 동일한 채널 루트를 사용하며 <root>/<channel>/tasks/ 아래에 권위 있는 JSON 레코드를 작성합니다.
활성 임대 레코드는 <root>/<channel>/claims/<task-id>.<owner>.json 아래에 있습니다.
모든 성공적인 작업 또는 임대 변이(mutation)는 기존 메시지 프로토콜을 통해 감사 이벤트도 게시합니다.
chat.py task create <channel> <task-id> --from <agent> --title <title>
chat.py task list <channel>
chat.py task show <channel> <task-id>
chat.py task update <channel> <task-id> --as <agent> [fields...]
chat.py task claim <channel> <task-id> --as <agent> --lease-seconds 300
chat.py task renew <channel> <task-id> --as <agent> --lease-seconds 300
chat.py task done <channel> <task-id> --as <agent>
chat.py task block <channel> <task-id> --as <agent>
chat.py task release <channel> <task-id> --as <agent>
chat.py task recover <channel> <task-id> --as <agent> \
--reason "stale session" --lease-seconds 300
chat.py task recover-pending <channel> --as <agent> \
[--resolve-publication rollback|published]
claim, renew 및 오래된 recover는 --lease-seconds, --lease 또는
--ttl을 허용합니다. 값은 양의 유한 기간이어야 합니다. claim은 준비된 작업을
in_progress로 전환하고, 소유자를 할당하며, 임대 레코드와 함께 만료 시간을 원자적으로 작성합니다.
소유자만 만료되지 않은 클레임을 갱신, 해제 또는 완료할 수 있습니다. task done은 활성 클레임을 원자적으로 지웁니다.
클레임이 없으면 직접적인 Task 3 전환을 유지합니다. task release는 유사하게 임대되지 않은
Task 3 전환을 유지합니다. 만료된 클레임은 절대 조용히 도난당하지 않습니다.
오래된 task recover는 새 소유자와 비어 있지 않은 이유가 필요하며 previous_owner,
previous_lease_expires_at 및 recovery_reason을 기록합니다.
충돌 후 task recover-pending <channel> --as <agent>는
내구성 트랜잭션 마커의 정리/롤백을 명시적으로 완료합니다. 절대 조용히 오래된 작업을 도난하거나 재할당하지 않습니다.
감사 게시를 증명할 수 없는 레거시 v1 applied 마커는 LEASE_TRANSACTION_PUBLICATION_UNKNOWN으로
실패 폐쇄됩니다. 운영자 검사 후 --resolve-publication rollback 또는 published를 사용하여 명령을 다시 실행하십시오.
create는 --owner, --depends-on, --files-hint, --acceptance 및
--branch를 허용합니다. 여러 값을 추가하려면 목록 옵션을 반복하십시오. update는
--title, --owner, --depends-on, --files-hint, --acceptance,
--branch 및 --status를 허용합니다. --clear-owner 또는 --clear-branch를 사용하여
nullable 필드를 다시 null로 설정하십시오. 일반 업데이트는 활성 임대를 변경할 수 없습니다.
대신 임대 명령을 사용하십시오. 목록 값은 쉼표로 구분될 수도 있습니다.
작업 상태는 open, in_progress, blocked, done 및 cancelled입니다.
done 및 cancelled는 최종 상태입니다. 전환은 open -> in_progress |
blocked | cancelled, in_progress -> open | blocked | done |
cancelled, blocked -> open | in_progress | cancelled를 허용합니다.
동일 상태 쓰기는 의도적으로 멱등적입니다. task done은 in_progress(또는
멱등 done)을 done으로 이동합니다. task block은 open, in_progress 또는
blocked를 blocked로 이동합니다. task release는 blocked, in_progress 또는
open을 open으로 이동합니다. 작업은 depends_on의 모든 ID가
상태가 done인 작업 레코드를 가질 때만 in_progress 또는 done으로 전진할 수 있습니다.
준비 상태는 메시지 텍스트가 아닌 작업 JSON 레코드에서 계산됩니다.
작업 및 임대 실패는 0이 아닌 값(종료 상태 2)이며 하나의 안정적인 코드를 포함합니다.
작업 코드에는 TASK_INVALID_COMMAND, TASK_INVALID_ARGUMENT,
TASK_INVALID_CHANNEL, TASK_CHANNEL_NOT_FOUND, TASK_NOT_FOUND,
TASK_ALREADY_EXISTS, TASK_INVALID_STATUS, TASK_INVALID_UPDATE,
TASK_INVALID_TRANSITION, TASK_DEPENDENCY_NOT_READY,
TASK_UNKNOWN_DEPENDENCY, TASK_DEPENDENCY_CYCLE,
TASK_PATH_OUTSIDE_WORKSPACE, TASK_LOCK_TIMEOUT, TASK_IO_ERROR,
TASK_AUDIT_FAILED가 있습니다. 임대 코드에는 LEASE_CONFLICT,
LEASE_RECOVERY_REQUIRED, LEASE_OWNER_MISMATCH, LEASE_NOT_EXPIRED,
LEASE_NOT_FOUND, LEASE_INCONSISTENT, LEASE_MUTATION_REQUIRED,
LEASE_INVALID_OWNER, LEASE_INVALID_TASK_ID, LEASE_INVALID_CHANNEL,
LEASE_INVALID_REASON, LEASE_INVALID_DURATION, LEASE_INVALID_TIMESTAMP,
LEASE_INVALID_RECORD, LEASE_REQUIRED_FIELD_MISSING, LEASE_UNKNOWN_FIELD,
LEASE_RECORD_ID_MISMATCH, LEASE_STORAGE_INVALID,
LEASE_PATH_OUTSIDE_WORKSPACE, LEASE_TRANSACTION_PENDING,
LEASE_TRANSACTION_CLEANUP_FAILED, LEASE_TRANSACTION_PUBLICATION_UNKNOWN,
LEASE_TRANSACTION_INVALID, LEASE_TRANSACTION_NOT_FOUND,
LEASE_TRANSACTION_RECOVERY_FAILED,
LEASE_AUDIT_FAILED, LEASE_AUDIT_ROLLBACK_FAILED가 있습니다. 임대 쓰기는
준비/적용/게시 단계가 있는 내구성 트랜잭션 마커를 사용합니다. 충돌 또는 정리 실패 후
task recover-pending/LeaseStore.recover_pending()이 명시적으로 롤백하거나
게시된 트랜잭션을 완료할 때까지 액세스는 실패 폐쇄됩니다.
경로 잠금은 작업 공간 기준 파일 및 디렉토리에 대한 독점 액세스를 조정합니다.
chat.py lock <channel> <paths...> --as <agent> [--lease-seconds 300]
chat.py check <channel> <paths...> [--as <agent>]
chat.py unlock <channel> <lock-id-or-path> --as <agent>
chat.py recover <channel> <lock-id-or-path> --as <agent> \
--reason "stale session" [--lease-seconds 300]
chat.py recover-pending <channel> --as <agent> \
[--resolve-publication rollback|published]
lock 및 recover는 --lease-seconds, --lease 또는 --ttl을 허용합니다. 대상은
잠금 ID 또는 정규화된 경로일 수 있습니다. 정규화는 작업 공간 기준 경로를 확인하고, 트래버설 및 루트/채널/심링크 이스케이프를 방지하며,
플랫폼 대소문자 규칙(Windows에서는 대소문자 구분 안 함)을 적용하고, Windows 예약 이름,
후행 점/공백, 제어 문자 및 단독 서로게이트를 거부합니다.
파일/파일 충돌 및 디렉토리/파일 중복은 충돌합니다. 소유자만 활성 잠금을 해제할 수 있습니다.
만료된 잠금은 previous_owner, previous_expires_at 및 recovery_reason을 기록하는
명시적 recover가 필요합니다. 변이(mutation)는 내용-원자 파일 게시, 권고적 파일 잠금 및
충돌 안전 트랜잭션 저널링을 사용합니다. 경로 잠금 오류는 PATH_LOCK_INVALID_PATH,
PATH_LOCK_PATH_OUTSIDE_WORKSPACE, PATH_LOCK_CONFLICT,
PATH_LOCK_RECOVERY_REQUIRED, PATH_LOCK_OWNER_MISMATCH,
PATH_LOCK_NOT_FOUND, PATH_LOCK_NOT_STALE, PATH_LOCK_INVALID_OWNER,
PATH_LOCK_INVALID_LOCK_ID, PATH_LOCK_INVALID_CHANNEL,
PATH_LOCK_INVALID_REASON, PATH_LOCK_INVALID_DURATION,
PATH_LOCK_INVALID_TIMESTAMP, PATH_LOCK_INVALID_RECORD,
PATH_LOCK_STORAGE_INVALID, PATH_LOCK_STORAGE_ERROR,
PATH_LOCK_TIMEOUT, PATH_LOCK_TRANSACTION_PENDING,
PATH_LOCK_TRANSACTION_CLEANUP_FAILED, PATH_LOCK_TRANSACTION_INVALID,
PATH_LOCK_AUDIT_FAILED, PATH_LOCK_AUDIT_ROLLBACK_FAILED와 같은
안정적인 코드와 함께 0이 아닌 값으로 종료됩니다.
채널 상태 요약 및 압축은 결정론적 state.md 아티팩트를 생성합니다.
chat.py state <channel> [--write] [--json] [--strict]
chat.py compact <channel> [--as <agent>] [--no-audit] [--json] [--strict]
state는 다음을 포함하는 파생 채널 요약을 렌더링하거나 출력합니다.
- 목표 / 주제 (
_meta.json에서) - 결정 (메시지 및 구조화된 레코드에서 추출)
- 열린 작업 (
tasks/*.json에서, 상태, 소유자, 임대, 종속성 포함) - 차단 요소 (작업 종속성 차단기, 차단된 작업 상태 및 차단 메시지)
- 소유자 및 임대 (활성 클레임, 작업 소유권 및 경로 잠금)
- 경로 잠금 (
locks/*.json에서 활성 경로 잠금) - 마지막 검증 증거 (수용 기준 및 확인 메시지)
compact는 원자적 임시 형제 교체(.state.md.tmp.*)를 사용하여 파생 요약을
<root>/<channel>/state.md에 쓰고 기본적으로 채널에 감사 가능한 state.compacted
메시지 이벤트를 게시합니다.
state.md는 엄격히 파생 아티팩트이며 절대 권위적이지 않습니다.
압축은 비파괴적입니다. 메시지 파일, 작업 레코드, 활성 클레임, 경로 잠금 또는 읽기 커서를
절대 삭제, 변이 또는 자르지 않습니다. 모든 소스 레코드는 불변의 기본 진실로 남습니다.
상태 오류는 STATE_INVALID_CHANNEL, STATE_CHANNEL_NOT_FOUND,
STATE_INVALID_RECORD, STATE_MALFORMED_SOURCE, STATE_RECORD_NOT_FOUND,
STATE_IO_ERROR, STATE_AUDIT_FAILED와 같은 안정적인 코드와 함께
0이 아닌 값으로 종료됩니다. --reply <seq>는 메시지를 이전 메시지에 스레드합니다.
모든 플래그는 python chat.py <cmd> --help를 참조하십시오.
어댑터 중립 이벤트 명령:
chat.py event post <channel> --from <agent> --type capability --harness <harness>
chat.py event post <channel> --from <agent> --type status --harness <harness> --status ready
chat.py event read <channel> [--type capability|status]
이벤트 본문은 schemas/agent-chat-event.schema.json에 대해 검증된 버전 관리 JSON입니다.
일반 마크다운 메시지는 변경되지 않으며 event read에서 무시됩니다.
폴더 구조
<root>/
review/ # 하나의 채널 = 하나의 그룹 채팅
_meta.json # 구성원, 주제, 생성일
state.md # 파생 상태 요약 (비권위적)
0001-alice-schema-draft.md # NNNN-<from>-<slug>.md, 머리말 + 본문
0002-bob-schema-review.md
tasks/ # 구조화된 작업 레코드
claims/ # 활성 임대 레코드
locks/ # 활성 작업 공간 경로 잠금
.cursors/bob.txt # 에이전트별 "마지막으로 읽은 시퀀스"
deploy/ # 두 번째 그룹 채팅, 별도의 시퀀스 공간
...