Skip to content

Argona7/coagent

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

coagent

Push-awareness hooks so Claude Code and Kimi CLI know what each other is doing on the same machine — without polling, without MCP calls, without either agent thinking about it.

When you flip between claude and kimi in two terminals all day, you keep re-explaining context: "I just edited this file", "Kimi already tried that approach, see the bridge", "don't redo what I just did". coagent kills that loop with three small Python hooks and one shared SQLite table.

  Claude Code session                       Kimi CLI session
  ──────────────────                        ────────────────
  SessionStart   ─┐                                   ┌─  SessionStart
                  │                                   │
  PostToolUse    ─┤   ┌──────────────────────────┐   ├─  PostToolUse
                  │   │ ~/.kimi-bridge/bridge.db │   │
                  ├──▶│       activity_log       │◀──┤
  Stop           ─┤   │  (project-scoped writes) │   ├─  Stop
                  │   └──────────────────────────┘   │
  SessionEnd     ─┘                                   └─  SessionEnd

Each agent writes what it just did (PostToolUse → one row, Stop → one checkpoint summary) and reads what the other did when it boots up (SessionStart → ≤2KB markdown digest of last 24h activity in this project, filtered to exclude itself).

Why

Two agents on one Mac is genuinely useful — Kimi has a different subscription quota, different strengths on long-context, different style. But they don't know about each other. Existing options are pull-only: you can install the kimi-bridge MCP server and call bridge_recent() manually, but the agent has to remember to do it, and SessionStart inject is the only place that information would actually be free.

coagent is the push layer: a 1KB stdout digest at session start that both agents see automatically, scoped to the project you're in (by cwd), limited to the last 24 hours, and excluding noise (Read/Grep/LS calls aren't worth surfacing — only Edit/Write/Bash/Shell get logged).

What "awareness" looks like in practice

When you cd into a project and start claude, the SessionStart hook injects this into the model context before the first prompt:

=== kimi-bridge: what kimi was doing here (last 24h) ===
[3m ago] checkpoint: Session: 12 tool uses, touched services/web_discovery.py, tests/test_web.py
[42m ago] edit: services/web_discovery.py
[42m ago] edit: tests/test_web.py
[1h ago] shell: pytest tests/test_web.py -v
[1h ago] checkpoint: Worked on services/web_discovery.py
=== End ===

Claude now knows Kimi was just here, what it touched, and what it ran. The reverse works the same way for Kimi (with one Kimi 1.41 Beta caveat documented below).

What this is not

  • Not a replacement for kimi-bridge — it complements it. coagent only writes to and reads from the activity_log table that kimi-bridge owns. You still need kimi-bridge installed for the database file and (if you want formal handoffs / shared notes / Claude→Kimi delegation) its MCP tools.
  • Not a chat relay — agents don't talk to each other in real time. Awareness is at session boundaries. By design.
  • Not project-wide noise — every row is scoped by cwd. Working in ~/Projects/foo/ never leaks into ~/Projects/bar/.

Install

0. Prerequisites

  • Python 3.11+
  • kimi-bridge installed (provides the SQLite file at ~/.kimi-bridge/bridge.db and the schema the hooks read/write)
  • Claude Code (any recent version) and/or Kimi CLI 1.41+

1. Clone

git clone https://github.com/Argona7/coagent ~/projects/coagent

The hooks are stdlib-only Python — there's nothing to pip install.

2. Wire Claude Code (~/.claude/settings.json)

Add these three hook entries (merge with whatever you already have under hooks):

{
  "hooks": {
    "SessionStart": [
      { "hooks": [{ "type": "command",
        "command": "BRIDGE_HOOK_ACTOR=claude /usr/bin/env python3 /Users/<you>/projects/coagent/hooks/inject_activity.py",
        "timeout": 5 }] }
    ],
    "PostToolUse": [
      { "matcher": "Edit|Write|Bash",
        "hooks": [{ "type": "command",
          "command": "BRIDGE_HOOK_ACTOR=claude /usr/bin/env python3 /Users/<you>/projects/coagent/hooks/log_tool_use.py",
          "timeout": 5 }] }
    ],
    "Stop": [
      { "hooks": [{ "type": "command",
        "command": "BRIDGE_HOOK_ACTOR=claude /usr/bin/env python3 /Users/<you>/projects/coagent/hooks/checkpoint.py",
        "timeout": 5 }] }
    ]
  }
}

3. Wire Kimi CLI (~/.kimi/config.toml)

⚠️ If your config has an inline hooks = [], delete that line first — TOML rejects mixing inline arrays with [[hooks]] array-of-tables.

[[hooks]]
event = "SessionStart"
command = "BRIDGE_HOOK_ACTOR=kimi /usr/bin/env python3 /Users/<you>/projects/coagent/hooks/inject_activity.py"
timeout = 5

[[hooks]]
event = "PostToolUse"
matcher = "WriteFile|StrReplaceFile|Shell"
command = "BRIDGE_HOOK_ACTOR=kimi /usr/bin/env python3 /Users/<you>/projects/coagent/hooks/log_tool_use.py"
timeout = 5

[[hooks]]
event = "Stop"
command = "BRIDGE_HOOK_ACTOR=kimi /usr/bin/env python3 /Users/<you>/projects/coagent/hooks/checkpoint.py"
timeout = 5

[[hooks]]
event = "SessionEnd"
command = "BRIDGE_HOOK_ACTOR=kimi /usr/bin/env python3 /Users/<you>/projects/coagent/hooks/checkpoint.py"
timeout = 5

4. Verify

Edit a file in either CLI, then check the DB:

sqlite3 ~/.kimi-bridge/bridge.db \
  "SELECT actor, action, summary, datetime(created_at, 'unixepoch') \
   FROM activity_log ORDER BY id DESC LIMIT 5;"

You should see your tool uses tagged with claude or kimi.

Then start the other CLI in the same project — the SessionStart inject should print a === kimi-bridge: what … was doing here === block.

How it works

Script Hook event Reads Writes
hooks/inject_activity.py SessionStart last 24h activity for cwd, excluding self + pending handoffs targeting self nothing
hooks/log_tool_use.py PostToolUse nothing one row per significant tool use (deduped within 30s)
hooks/checkpoint.py Stop / SessionEnd last hour's tool use for self one summary row

Both agents run the same scripts. The only difference is the BRIDGE_HOOK_ACTOR env var in the wrapping command, which tags rows on write and filters them on read.

Tool name normalization

Claude Code and Kimi CLI use different names for the same actions. The logger unifies them:

Claude name Kimi name Stored summary
Edit, Write, MultiEdit WriteFile, StrReplaceFile edit: <file_path>
Bash Shell shell: <command-truncated-to-80-chars>

Read-only / introspection tools are skipped entirely so the digest stays signal-heavy: Read, Grep, Glob, LS, ListDir, BashOutput, anything starting with bridge_, handoff_, or mcp__claude-mem__.

Anti-loop and dedupe

  • 30s dedupelog_tool_use.py UPDATEs created_at instead of inserting if the same actor logged the same summary within 30 seconds. Prevents burst-noise (e.g. 5 quick edits to the same file) from filling the DB.
  • stop_hook_active guardcheckpoint.py exits immediately when Claude signals it's already inside a Stop hook chain. Without this, summarizing triggers another Stop, which triggers another summary, ad infinitum.
  • Self-exclusion — the inject hook filters actor != $BRIDGE_HOOK_ACTOR, so each agent never sees its own activity echoed back at session start.

Failure mode: silent

Every hook exits 0 on any error — malformed stdin, missing DB, locked DB, import failure, you name it. Hooks must never break the host CLI session, so the worst case is "this session doesn't get a digest" — the agent keeps working as if coagent weren't installed.

Output cap

The injected digest is hard-capped at 2048 bytes. Beyond that we trim oldest entries first and append (... older entries trimmed). Claude Code's SessionStart inject limit is 10KB so we have plenty of headroom; the cap is about signal density, not the limit.

Kill switch

Three ways to disable it:

  1. Per-sessionBRIDGE_HOOK_ACTOR=disabled in the hook command. Hook still runs and exits 0, but does no DB I/O.
  2. Permanently — remove the hook entries from ~/.claude/settings.json / ~/.kimi/config.toml. The hook scripts themselves can stay on disk.
  3. Schema-levelmv ~/.kimi-bridge/bridge.db ~/.kimi-bridge/bridge.db.off. Hooks see the missing DB and exit silently. Useful for debugging without piling on writes.

Tested versions

  • Claude Code: stable channel (Opus 4.7)
  • Kimi CLI: 1.41.0 (Beta)

Known Kimi 1.41 Beta limitation

The SessionStart hook fires correctly in Kimi (you'll see Triggering 1 hooks for SessionStart in ~/.kimi/logs/kimi.log) and the DB writes happen, but the stdout content from the inject hook is not surfaced into the model context in 1.41 Beta — Kimi can't "see" the digest unless it explicitly calls bridge_recent via the kimi-bridge MCP tool.

The fallback works: tell Kimi to call bridge_recent(20) and handoff_list() at session start (e.g. via your AGENTS.md). When Kimi ships a fix for SessionStart inject, no script changes will be needed here.

Claude Code's SessionStart inject works as advertised — the asymmetry is purely on the Kimi side.

Tests

cd ~/projects/coagent
python3 -m pytest tests/test_hooks.py -v

34 subprocess-driven tests covering: empty DB, cwd filtering, actor exclusion, handoff inclusion, 2KB truncation, all tool name mappings, noisy-tool skip, 30s dedupe, stop_hook_active guard, no-recent-activity short-circuit, disabled kill switch, and malformed JSON tolerance.

Layout

coagent/
├── hooks/
│   ├── _common.py            # shared helpers: stdin, env, DB, time formatting
│   ├── inject_activity.py    # SessionStart digest
│   ├── log_tool_use.py       # PostToolUse logger w/ 30s dedupe
│   └── checkpoint.py         # Stop / SessionEnd summarizer
├── tests/
│   ├── _dbutil.py            # mini schema mirror so tests don't need kimi-bridge
│   ├── conftest.py           # makes tests/ importable
│   └── test_hooks.py         # 34 subprocess tests
├── pyproject.toml
├── LICENSE                   # MIT
└── README.md                 # you're here

License

MIT — see LICENSE.

About

Push-awareness hooks so Claude Code and Kimi CLI know what each other is doing on the same machine — without polling, without MCP calls.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages