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:
整条链路:
What the private chat looks like:
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 tokendedup — same report never triggers twicecommit shafilter — avoids re-reviewing the same commit- Supports both
threadandreplyresponse styles pending.jsonfor 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.