[AI_TOOLS_LOG]// APRIL 16, 2026 // 6 MIN READ

I Bolted an Argue Bot onto Our Feishu Code Review

#AI#FEISHU#AUTOMATION#CODE-REVIEW

This is not about fighting review with AI.

The real situation is the opposite.

Our team's review system was actually put together carefully. It covers resource format, dependencies, threading, memory, logging, serialization, commit messages — built up over time by the team. It has real teeth.

My attitude toward it has always been: it's genuinely valuable. I just wanted to connect it more naturally to my own workflow.

First, let's be clear: this is not the first-pass review

This article is about the review that happens after you push — the Feishu report that lands when an MR is submitted.

My local layer — pre-commit hooks, Claude Code review, the memory pipeline — is a different story, upstream of all this. I'll write that up separately.

So don't read this as "I replaced the first-pass review with a bot." The more accurate framing is:

I added an argue bot after the post-MR Feishu review comes in.

Why add another layer at all

Because the post-submission review has one structural limitation: it sees the diff, the commit, the MR description — but it doesn't know my dev context at the time of writing. It doesn't know the design tradeoff I was making, or why I chose this approach over the alternative.

This tends to produce a predictable mix:

  • Some issues are exactly right, and genuinely blocking
  • Some have the right direction but lower priority than flagged
  • Some don't hold up given my actual context

That's why I built the argue bot. Not to fight the review, but to fill in the layer it structurally can't see:

The rule-based review is good. It just doesn't always know why I wrote it this way.

My baseline attitude toward the review system

If both the CI/CD review and my local toolchain agree something is a real problem and genuinely blocking — I fix it without hesitation.

For lower-severity things, like an imprecise commit message, I treat it as feedback: note it, be more careful next time, and quietly update my commit skill if it keeps showing up.

The way I think about it: the review is pushing my habits forward, and my local toolchain is adapting to match. It's not adversarial. Most of the time it's convergent.

I actually like reading review reports

Worth saying explicitly: I didn't build this bot because I hate reading review reports.

I read them even when the issues aren't mine. Because there's usually useful signal there:

  • What the team is paying attention to right now
  • Which problems keep recurring
  • Which conventions are worth internalizing into my own habits

So reviews are already a learning channel for me.

Looking across reports, the recurring patterns become obvious fast: production code still logging to Log.e(), debug URLs slipping into commits, commented-out code left in, commit messages that just say fix bug. Each one is a small reminder; seeing the same one ten times tells you something about where the team is still fragile.

What I actually wanted to solve was not "avoid reading the report." It was:

When a report is long, items are mixed, and I can't immediately tell signal from noise — I want one layer of judgment that's calibrated to my own context.

What the bot actually does

The pipeline, then the conversation:

整条链路:

Review Argue Bot workflow

What the private chat looks like:

Private chat conversation example

The three things I care most about in this design:

  • The dev group is read-only. The bot never posts there.
  • I decide whether to process anything. The bot only asks.
  • What comes back is not a copy of the report — it's a processed judgment.

Why all / mine / skip

The three choices exist mainly because of token budget, not product elegance.

My tokens aren't unlimited. If budget is comfortable I'll run all. In practice I usually choose mine — I care about my own issues; someone else's argue results don't help me. skip is for when I already know the situation or just don't have the budget right now.

It's a budget allocation decision, not a UX feature:

Given limited tokens, I put analysis capacity where it's most useful.

Two engines, for mutual fallback

I hooked up both Claude and Codex.

The reason is simple: whichever has more budget right now, I use that one. If Claude hits its 5h window limit, the bot switches to Codex. If one seems degraded, I switch manually. The confirmation message supports mine codex or all claude inline.

They cover each other.

The engineering details that make it actually work

If the bot were just "poll Feishu, call an AI," it would be a one-time demo.

What keeps it running reliably:

  • doc token dedup — same report never triggers twice
  • commit sha filter — avoids re-reviewing the same commit
  • Supports both thread and reply response styles
  • pending.json for confirmations I haven't acted on yet
  • 7-day auto-expire for pending items, 30-day cleanup for rejected ones
  • In-place message edit — no log spam in the private chat

The sha and doc token filters matter most to me. A duplicate trigger doesn't just waste a message — it burns real tokens.

One engineering detour worth mentioning: I originally designed the argue archive to be filed by date in Feishu folders:

  • 2026 / 04 / 16 / xxx doc

Cleaner to browse later. But I discovered I don't have write permission into specific Feishu folders. So I fell back to encoding the info in the document title instead:

  • Argue | 2026-04-16 | cursor_sync_optimize

Not ideal, but searchable enough.


Implementation is the usual stack: lark-cli for Feishu API, Claude CLI and Codex CLI for argue, wrapped in a polling loop with dedup, a pending queue, in-place message editing, and archive logic. The hard part was never getting the commands to run — it was doing all the edge-case plumbing until it fit well enough into my actual workflow.

SX
Written by sunxu

Android engineer. Code and words.

© 2026 sunxu · CC BY-NC 4.0Non-commercial · Attribution required