Research-Code-Agent is an OpenCode Skill for research experiment workflows.
Research-Code-Agent 是面向 OpenCode 的科研实验工作流 Skill,用于让 OpenCode 在科研代码项目中安全地计划、运行、记录、总结和诊断实验。
第一版默认服务于“飞书自然语言入口 + OpenCode 执行科研项目”的使用场景,但 RCA 本身不负责飞书接入。Feishu、opencode-feishu、botmux、systemd、tmux 等都是外部入口或运行设施;RCA 从 OpenCode 已进入项目目录之后开始工作。
第一用户是在服务器上做深度学习实验、论文复现、baseline / ablation / metrics 整理的个人研究者。
当前能力:
- OpenCode global Skill:
skills/rca/SKILL.md - RCA CLI:
bin/rca - project-local context:
RCA.md - project-local workspace:
.rca/ - structured profile:
.rca/profile.json - experiment ledger:
.rca/experiments.json - standard run wrapper:
.rca/scripts/run_experiment.sh - consistency check:
rca check - legacy optional tools under
tools/
技术栈:bash + Python 标准库。核心 RCA 工作流无外部依赖。飞书入口是可选外围能力:推荐 NeverMore93/opencode-feishu 或 botmux;自研 Python Feishu bridge 仅作为 legacy fallback,可能需要 Feishu Channel SDK Python(lark-channel-sdk)。不存储 Feishu 凭证。
当前 RCA 不做:Feishu bridge、MCP Server、OpenCode Plugin、botmux 集成、多 CLI 平台、Dashboard、复杂 MLOps、消息卡片、WebSocket bridge、Web terminal、Agent runtime、LLM provider 管理、复杂权限系统、Python command router。
Use RCA after the AI coding assistant has initialized the project:
existing research code project
-> OpenCode init / Codex project context
-> rca init
-> AI reads README, training/eval scripts, configs, data flow, outputs, paper materials
-> AI fills RCA.md and .rca/profile.json
-> user asks for an experiment in natural language
-> RCA proposes an experiment plan
-> user confirms
-> RCA runs .rca/scripts/run_experiment.sh
-> RCA updates .rca/experiments.json
-> AI summarizes results in the conversation
Important rules:
- Run OpenCode/project initialization first, then
rca init. rca initscaffolds context and workflow files; it is not a deep scanner.- The AI assistant should fill
RCA.mdand.rca/profile.jsonafter reading the actual project. - RCA must propose an experiment plan before launching long experiments.
- The user must explicitly confirm the plan;
.rca/scripts/run_experiment.shrequires--confirm. - Long experiments must go through
.rca/scripts/run_experiment.sh. .rca/scripts/run_experiment.shuses.rca/experiments.lockor.rca/experiments.lockdirand atomic file replacement for per-run summaries and.rca/experiments.json..rca/experiments.jsonis the first local source for later comparison and result lookup.
Keep this repository somewhere stable, for example:
~/Research-Code-AgentMake scripts executable:
chmod +x ~/Research-Code-Agent/init_research_project.sh
chmod +x ~/Research-Code-Agent/bin/rca
chmod +x ~/Research-Code-Agent/tools/*.sh
chmod +x ~/Research-Code-Agent/tools/*.py
chmod +x ~/Research-Code-Agent/examples/*.shAdd bin/ to PATH if you want to run rca directly:
export PATH="$HOME/Research-Code-Agent/bin:$PATH"Install the OpenCode Skill by copying or symlinking skills/rca/SKILL.md into your OpenCode global skills directory according to your local OpenCode setup. This repository does not modify your home directory automatically.
From any research project root:
rca initIf rca is not on PATH, run:
~/Research-Code-Agent/bin/rca initrca init creates:
.rca/
README.md
profile.json
experiments.json
scripts/
run_experiment.sh
runs/
plans/
RCA.md
It does not modify source code, does not write secrets, and does not overwrite RCA.md, .rca/profile.json, or .rca/experiments.json unless --force is passed.
The legacy init_research_project.sh remains for existing release users and copies the older optional tools/, docs, and Feishu-related templates. New v0.7.0 workflows should prefer rca init.
# 1. Initialize after OpenCode has initialized/read the project
rca init
# 2. Ask the AI assistant to read RCA.md and fill project-specific context
# from README, train/eval scripts, configs, outputs, and paper materials.
# 3. Run toy RCA recording test
mkdir -p examples
printf 'echo "UF1: 82.4"\n' > examples/toy_success.sh
chmod +x examples/toy_success.sh
./.rca/scripts/run_experiment.sh --name toy_success --note "跑一次 toy success,验证 RCA 记录流程" --confirm -- bash examples/toy_success.sh
# 4. Check workspace consistency
rca check# 1. Initialize Research-Code-Agent
bash init_research_project.sh
# 2. Verify Feishu notification
./tools/test_feishu_notify.sh
# 3. Add local paper PDF
mkdir -p papers
cp /path/to/paper.pdf papers/
# 4. Create local paper context template
./tools/init_paper_context.sh
# 5. Ask your Agent to fill PAPER_CONTEXT.md based on:
# - papers/*.pdf
# - README.md
# - train.py / main.py
# - configs/
# - scripts/Files under papers/ and PAPER_CONTEXT.md are local context files and are ignored by Git. This workflow only gives the Agent paper context before code changes; it is not a knowledge base and does not parse PDFs automatically.
Research-Code-Agent is the tool development repository. Do not git clone it into each baseline project.
Recommended baseline setup is via GitHub Release tarball:
wget https://github.com/Huangmr0719/Research-Code-Agent/releases/latest/download/research-code-agent.tar.gz
tar -xzf research-code-agent.tar.gz
bash research-code-agent/init_research_project.sh
rm -rf research-code-agent research-code-agent.tar.gzThe baseline project should only keep the initialized workflow files such as AGENTS.md, RCA.md, .rca/, tools/, templates/, README_AGENT_WORKFLOW.md, and ignore rules. Do not leave a nested Research-Code-Agent/.git in the baseline project.
Current development repository may still be named research-agent-template. The recommended future GitHub repository name is Research-Code-Agent; release package directory name should be research-code-agent.
Original command:
python train.py --config configs/default.yamlUse the RCA launcher:
./.rca/scripts/run_experiment.sh \
--name baseline_default \
--note "跑一次默认 baseline,作为后续实验对照" \
--confirm \
--task-type baseline \
--config configs/default.yaml \
-- python train.py --config configs/default.yamlThe launcher saves command.sh, stdout.log, stderr.log, timing metadata, summary.json, and updates .rca/experiments.json.
It refuses to run without --confirm, uses a lock for ledger updates, and writes summary/index JSON files atomically.
In opencode.json, configure .rca/scripts/run_experiment.sh as ask, not unconditional allow. RCA confirmation is the first boundary; OpenCode tool approval is the second boundary.
Legacy lower-level wrapper, kept for compatibility:
./tools/run_with_feishu_notify.sh --name baseline_default -- python train.py --config configs/default.yamlYou can add an experiment note:
./tools/run_with_feishu_notify.sh \
--name exp_042 \
--note "去除 region mask 模块,验证该模块对 UF1/UAR 的贡献" \
-- python train.py --config configs/exp_042.yamlThis legacy wrapper is optional and should not become a second experiment record path. The standard RCA path is .rca/scripts/run_experiment.sh.
After initializing a project, verify Feishu notification:
./tools/test_feishu_notify.shIf you receive the test card/message, the notification pipeline is working.
tools/feishu_notify.py defaults to Feishu card mode. It first tries to detect installed feishu or lark CLI binaries with common card/text send commands.
If you use lark-cli, set one target:
export FEISHU_CHAT_ID="oc_xxx"
# or
export FEISHU_USER_ID="ou_xxx"LARK_CHAT_ID and LARK_USER_ID are also accepted. If needed, set FEISHU_CLI_AS=bot or FEISHU_CLI_AS=user.
If your CLI uses a different command format, set:
export FEISHU_CLI_CARD_COMMAND="feishu send --card"
export FEISHU_CLI_TEXT_COMMAND="feishu send --text"The configured command should accept the notification payload as its final argument. If your CLI needs the payload in the middle of the command, use {payload}:
export FEISHU_CLI_CARD_COMMAND='feishu send --card-json {payload}'If your CLI needs a payload file, use {payload_file}:
export FEISHU_CLI_CARD_COMMAND='feishu send --card-file {payload_file}'For lark-cli im +messages-send --msg-type interactive --content, use {card} to pass only the card content object:
export FEISHU_CLI_CARD_COMMAND='lark-cli im +messages-send --chat-id oc_xxx --msg-type interactive --content {card}'For compatibility with older setup, FEISHU_CLI_SEND_COMMAND is also supported. To force plain text notifications:
export FEISHU_NOTIFY_MODE=textNo Feishu credential should be written into this repository.
If Feishu sending fails, the script prints the notification content to stdout and exits non-zero. The experiment wrapper does not fail the experiment just because notification delivery failed.
tools/summarize_experiment.py writes:
experiments/summaries/<experiment_name>.summary.json
experiments/summaries/<experiment_name>.summary.md
summarize_experiment.py is fact-only. It extracts:
note: user-provided experiment intent from--notestatus: success, failed, or interruptedfacts: exit code, signal, command, host, git commit, start/end time, duration, log pathmetricslog_tail: last 80 log linestraceback: short traceback/error snippet if available
If metrics.json or result.json exists, JSON metrics are preferred. Otherwise the script extracts common metrics from logs:
accuracyaccF1UF1UARlossval_lossbest_epoch
tools/project_results_adapter.py is a project-level metrics adapter template.
When a baseline project already produces structured metrics (e.g., outputs/metrics.json), the adapter extracts them before fallback to log regex.
Example outputs/metrics.json:
{
"metrics": {
"UF1": 0.82,
"UAR": 0.80,
"loss": 0.41
}
}After running the wrapper, summary.json and the Feishu card will show these metrics with metrics_source: adapter.
If the adapter fails or finds no structured file, summarize_experiment.py falls back to metrics.json / result.json / log regex. Adapter failure never blocks summary generation, OpenCode analysis, or Feishu notification.
Adapt project_results_adapter.py to each baseline project's output format. Do NOT commit project-specific logic back into the mother template repository.
Compare experiments from generated summary files:
python tools/compare_experiments.py \
--summaries experiments/summaries \
--baseline baseline_default \
--output experiments/comparisons/compare.mdcompare_experiments.py only reads *.summary.json files under the summaries directory. It does not read full logs.
Comparison output is a local experiment artifact. experiments/ is ignored by default and should not be committed unless you explicitly decide to preserve a cleaned result elsewhere.
tools/analyze_with_agent.py reads the summary JSON and calls OpenCode:
opencode run "<prompt>"Only note, facts, metrics, traceback snippets, and the last 80 log lines are sent to the agent. The analysis is written to summary.json under the analysis field and never overwrites facts.
The analysis schema is:
{
"concise_summary": "...",
"evidence": [],
"possible_causes": [],
"next_steps": [],
"confidence": "low|medium|high"
}The prompt asks OpenCode to return concise Chinese analysis. If OpenCode is unavailable or fails, notifications still send. The analysis summary becomes:
Agent 分析不可用。请查看 facts 和 log tail。
Feishu cards show 实验备注, 运行概览, 核心指标, Agent 分析, 日志摘要, and 运行命令.
Feishu is an optional remote entry layer, not the RCA product core. If you need Feishu access, the recommended route is NeverMore93/opencode-feishu:
Feishu
-> opencode-feishu OpenCode plugin
-> OpenCode natural-language workflow
-> Research-Code-Agent tools
-> Feishu CardKit reply
This route keeps the product boundary simple:
- Feishu users speak natural language.
- Users do not need to remember
/summary,/compare,/run, or RCA command names. - OpenCode decides which RCA tool to use.
.opencode/commands/files are action templates for OpenCode, not user-facing commands.- Long experiments must still use
tools/run_with_feishu_notify.sh. - Experiment summaries, comparison, and log analysis remain provided by RCA tools.
Templates:
templates/opencode-feishu.plugin.example.jsonfor~/.config/opencode/opencode.jsontemplates/feishu.plugin.example.jsonfor~/.config/opencode/plugins/feishu.json
See:
docs/opencode-feishu-adoption.mddocs/opencode-feishu-throwaway-test.md
opencode-lark is now a historical evaluation item, not the current main route. OpenCode SDK evaluation is a backup option, not the current main route.
v0.5.0 added an optional thin bridge for remote OpenCode access from Feishu. As of v0.6.5, this is a legacy fallback route:
Feishu Channel SDK Python
-> open_id whitelist
-> sqlite message_id dedupe
-> per-chat lock
-> immediate "收到,处理中。"
-> local OpenCode server at 127.0.0.1:4096
-> static Feishu card replies, with markdown fallback
v0.6.0 keeps the bridge thin and adds stable deployment support plus opencode-pty guidance for background session management. The intended long-task path is:
Feishu
-> bridge
-> OpenCode
-> opencode-pty
-> tools/run_with_feishu_notify.sh / RCA tools
-> OpenCode summary
-> Feishu static card
The legacy bridge does not implement /status, /summary, /run, or any Python command router. It does not use Vercel Chat SDK, @larksuite/vercel-chat-adapter, Feishu CLI, DingTalk MCP, webhook, public ports, tunneling, streaming progress, approval cards, MCP, Hermes, botmux, or multi-platform routing. Feishu is the only remote entrypoint. OpenCode is responsible for understanding and executing the user request.
Long-running experiments must still be launched through:
./tools/run_with_feishu_notify.sh --name <experiment_name> -- <command>The preferred strategy is:
- Users keep speaking natural language in Feishu.
- Users do not need to remember
/summary,/compare,/run, or other command syntax. - OpenCode should understand the task and choose the right RCA tool.
- RCA tools remain the stable experiment toolbox.
AGENTS.md,.opencode/commands/,opencode.json, and permissions define OpenCode behavior.- Use RCA core files first:
AGENTS.md,RCA.md,.rca/profile.json,.rca/experiments.json, and.rca/scripts/run_experiment.sh. - Keep the Python bridge as a legacy fallback transport.
- Treat Feishu integrations,
opencode-lark, and OpenCode SDK work as optional outer layers.
The .opencode/commands/ files are OpenCode action templates. They are not user-facing commands. A Feishu user can still say “看最近实验”, “比较最近两次”, “跑一下 toy_success”, or “分析失败原因”.
See:
docs/requirements.mddocs/implementation-plan.mddocs/rca-final-convergence.mddocs/opencode-native-simplification.mddocs/opencode-native-smoke-test.mddocs/opencode-feishu-adoption.mddocs/opencode-feishu-throwaway-test.mddocs/opencode-lark-evaluation.mddocs/opencode-lark-throwaway-test.mddocs/opencode-sdk-evaluation.md
Create a Feishu self-built app and enable WebSocket event subscription for local/server development. Subscribe to the message receive event for bot chats, grant bot message send/receive scopes, then reinstall the app into the tenant and target chat. Record:
- app id
- app secret
- allowed user
open_idvalues
Only open_id is used for the bridge whitelist.
Run OpenCode only on localhost:
export OPENCODE_SERVER_PASSWORD="<long-random-password>"
opencode serve --hostname 127.0.0.1 --port 4096Before the bridge starts, it checks OpenCode health and http://127.0.0.1:4096/doc. The bridge uses the standard OpenCode server API:
GET /global/healthPOST /sessionPOST /session/{sessionID}/messageGET /session/{sessionID}/messagePOST /session/{sessionID}/abort
When OPENCODE_SERVER_PASSWORD is set, OpenCode protects the HTTP API with Basic Auth. The default username is opencode; set OPENCODE_SERVER_USERNAME if your server overrides it. The bridge reads both values and sends the matching Authorization header.
The bridge stores chat_id -> session_id in sqlite, so a Feishu chat can continue using the same OpenCode session after the bridge restarts. If a request times out, the bridge calls POST /session/{sessionID}/abort and replies with a timeout notice.
If opencode serve restarts and the stored session no longer exists, the bridge recreates the OpenCode session for that chat_id, updates sqlite, and retries the current message once. It does not retry indefinitely.
Copy the example env file to a private location:
sudo mkdir -p /etc/research-code-agent
sudo cp templates/feishu_bridge.env.example /etc/research-code-agent/feishu-bridge.env
sudo chmod 600 /etc/research-code-agent/feishu-bridge.env
sudo $EDITOR /etc/research-code-agent/feishu-bridge.envRequired values:
LARK_APP_ID=cli_xxx
LARK_APP_SECRET=xxx
RCA_FEISHU_ALLOWED_OPEN_IDS=ou_xxx,ou_yyy
OPENCODE_BASE_URL=http://127.0.0.1:4096
OPENCODE_SERVER_USERNAME=opencode
OPENCODE_SERVER_PASSWORD=change-this-long-random-password
RCA_PROJECT_DIR=/path/to/baseline-project
BRIDGE_DB_PATH=/path/to/baseline-project/.rca/feishu_bridge.sqlite3
BRIDGE_LOG_PATH=/path/to/baseline-project/.rca/feishu_bridge_audit.jsonl
BRIDGE_TIMEOUT_SECONDS=600
BRIDGE_REPLY_FORMAT=card
BRIDGE_HEALTHCHECK_ENABLED=true
BRIDGE_HEALTHCHECK_INTERVAL_SECONDS=300
BRIDGE_HEALTHCHECK_FAILURE_THRESHOLD=3
BRIDGE_ADMIN_CHAT_ID=
BRIDGE_AUDIT_MAX_BYTES=10485760
BRIDGE_AUDIT_BACKUP_COUNT=5
BRIDGE_PROCESSED_MESSAGE_RETENTION_DAYS=7The copied env file is private configuration and must not be committed.
Install Feishu Channel SDK Python in the runtime environment used by systemd:
python3 -m pip install --user lark-channel-sdkRun the first server test in foreground before installing systemd:
git clone https://github.com/Huangmr0719/Research-Code-Agent.git
cd /path/to/baseline-project
bash /path/to/Research-Code-Agent/init_research_project.sh
cp templates/feishu_bridge.env.example feishu_bridge.env
chmod 600 feishu_bridge.env
mkdir -p .rca
chmod 700 .rcaEdit feishu_bridge.env, rotate the Feishu App Secret if it was used during local testing, then start OpenCode in terminal 1:
set -a
. ./feishu_bridge.env
set +a
opencode serve --hostname 127.0.0.1 --port 4096Start the bridge in terminal 2:
python3 tools/feishu_opencode_bridge.py --env feishu_bridge.envIn Feishu, send a simple project question and confirm:
- the bot immediately replies
收到,处理中。; - the final reply is a static card by default;
- setting
BRIDGE_REPLY_FORMAT=markdownfalls back to markdown/text; - OpenCode can see and use
opencode-ptyif installed; - long experiments are launched through
tools/run_with_feishu_notify.sh.
The bridge prompt is only a behavior hint, not a security boundary. Real restrictions must come from:
opencode.jsonpermission rules;- the Unix user running the systemd services;
- filesystem ownership and write permissions;
- keeping
opencode servebound to127.0.0.1.
Use a restricted service user if the server is shared. Do not give OpenCode write access to datasets, checkpoints, private credentials, or unrelated projects unless needed.
Recommended local file permissions:
chmod 600 feishu_bridge.env
chmod 700 .rca
chmod 600 .rca/feishu_bridge.sqlite3
chmod 600 .rca/feishu_bridge_audit.jsonlIf sqlite or audit files do not exist yet, run the bridge once and then apply the file chmod commands. feishu_bridge.env, .rca/, and audit logs are ignored by Git. Audit is local troubleshooting material only; it is not returned to Feishu.
templates/opencode.remote.example.json contains a lightweight permission-policy example for the remote Feishu entry. Treat it as a checklist and adapt it to your installed OpenCode version. It should express these boundaries:
- Allow reading project docs,
AGENTS.md,PAPER_CONTEXT.md, logs, andexperiments/summaries/. - Allow Research-Code-Agent tools for summary, comparison, and notification workflows.
- Allow long experiments only through
tools/run_with_feishu_notify.sh. - Allow
opencode-ptyto start, read, and abort controlled background sessions inside the project. - Deny or require confirmation for
feishu_bridge.env,.env, secrets, SSH keys, token files, destructive file operations, uploads,git push, naked long training commands, and pty access outside the project.
opencode-pty is a background session manager, not a permission bypass. It must obey OpenCode permissions and Linux filesystem access.
v0.5.3 defaults to static Feishu cards for final OpenCode replies:
BRIDGE_REPLY_FORMAT=cardSet this to markdown if card sending is incompatible with the current Feishu tenant or SDK behavior:
BRIDGE_REPLY_FORMAT=markdownThe card mode is static display only. It does not use buttons, card callbacks, streaming updates, approval actions, or command values. If card sending fails, the bridge automatically falls back to markdown/text replies so the user still receives the result.
The bridge applies two separate safety filters before replying to Feishu:
- OpenCode part filtering avoids structural leakage from
reasoning,thinking,tool,tool_result,system,debug, and internal message parts. redact_sensitive_textreduces content leakage in the final visible reply by replacing common tokens, API keys, private key blocks, and secret-like env lines with[REDACTED].
Audit logs are local troubleshooting material. They are not sent back to Feishu, are ignored by Git, and should be protected with normal file permissions.
The bridge can periodically call OpenCode GET /global/health:
BRIDGE_HEALTHCHECK_ENABLED=true
BRIDGE_HEALTHCHECK_INTERVAL_SECONDS=300
BRIDGE_HEALTHCHECK_FAILURE_THRESHOLD=3
BRIDGE_ADMIN_CHAT_ID=oc_xxxAfter consecutive failures reach the threshold, the bridge writes audit events and, if BRIDGE_ADMIN_CHAT_ID is set, sends a Feishu alert. Without an admin chat, it only writes audit. Healthcheck runs in the background and does not block normal message handling. Recovery is written to audit.
Audit rotation is built in:
BRIDGE_AUDIT_MAX_BYTES=10485760
BRIDGE_AUDIT_BACKUP_COUNT=5When the audit file exceeds the size limit, it is rotated locally without external logrotate. Rotation failures are printed to stderr and do not stop bridge message handling.
Message dedupe rows are cleaned on bridge startup:
BRIDGE_PROCESSED_MESSAGE_RETENTION_DAYS=7This only cleans old processed_messages; chat_sessions is retained so Feishu chats can continue using their OpenCode sessions.
opencode-pty is optional background session management for OpenCode. It does not replace tools/run_with_feishu_notify.sh and does not change the bridge into a router.
Use it this way:
- Confirm
opencode-ptyis available to the OpenCode runtime. - Ask OpenCode from Feishu to start a controlled background session.
- Inside the session, run a wrapped command such as:
./tools/run_with_feishu_notify.sh --name toy_success -- bash examples/toy_success.sh- Ask OpenCode to read the pty session output buffer and generated summary.
- Ask OpenCode to abort the controlled pty session if needed.
Avoid these patterns:
- bridge parsing the Feishu message and directly calling
opencode-pty; - pty sessions running naked long commands instead of
tools/run_with_feishu_notify.sh; - pty sessions executing arbitrary user-provided shell;
- pty reading non-project directories or sensitive files.
Copy the service templates and edit paths:
sudo cp templates/systemd/opencode-serve.service /etc/systemd/system/opencode-serve.service
sudo cp templates/systemd/rca-feishu-opencode-bridge.service /etc/systemd/system/rca-feishu-opencode-bridge.service
sudo $EDITOR /etc/systemd/system/opencode-serve.service
sudo $EDITOR /etc/systemd/system/rca-feishu-opencode-bridge.serviceReplace /opt/baseline-project and /etc/research-code-agent/feishu-bridge.env with your actual server paths. Do not put secrets directly in service files.
Then enable both services:
sudo systemctl daemon-reload
sudo systemctl enable opencode-serve.service
sudo systemctl enable rca-feishu-opencode-bridge.service
sudo systemctl start opencode-serve.service
sudo systemctl start rca-feishu-opencode-bridge.service
sudo systemctl status opencode-serve.service
sudo systemctl status rca-feishu-opencode-bridge.service
sudo systemctl restart rca-feishu-opencode-bridge.serviceCheck logs:
journalctl -u opencode-serve.service -f
journalctl -u rca-feishu-opencode-bridge.service -f
tail -f .rca/feishu_bridge_audit.jsonl
curl -u opencode:$OPENCODE_SERVER_PASSWORD http://127.0.0.1:4096/global/healthFor foreground testing on macOS, use:
python3 tools/feishu_opencode_bridge.py --env feishu_bridge.env- Non-whitelisted
open_idmessages are ignored. - Duplicate
message_idvalues are skipped via sqlite. - The same
chat_idcan process only one message at a time. - If a chat is busy, the bridge replies with a short busy message.
- OpenCode output is sent as a static Feishu card by default; long output or card failures fall back to Feishu text chunks.
- If OpenCode times out or fails, the bridge replies with a short failure message and logs the exception.
- The bridge only forwards text messages in this prototype.
- Feishu has no reply: check app WebSocket/event subscription, bot permissions,
RCA_FEISHU_ALLOWED_OPEN_IDS, andjournalctl -u rca-feishu-opencode-bridge.service -f. - Card sending fails: set
BRIDGE_REPLY_FORMAT=markdown, restart the bridge, and check audit forcard_send_failed. - OpenCode healthcheck failed: run
systemctl status opencode-serve.serviceandcurl -u opencode:$OPENCODE_SERVER_PASSWORD http://127.0.0.1:4096/global/health. session_recreatedappears: OpenCode was likely restarted and the bridge created a fresh session for that chat.open_idnot in whitelist: add the user's Feishuopen_idtoRCA_FEISHU_ALLOWED_OPEN_IDSand restart the bridge.- Env permission errors: use
chmod 600 feishu_bridge.env,chmod 700 .rca, then restart. - systemd cannot find Python or OpenCode: edit
ExecStartto an absolute path fromwhich python3orwhich opencode. lark_channelis missing: installlark-channel-sdkin the same Python environment used by systemd.opencode-ptyis unavailable: install or expose it to OpenCode, then ask OpenCode to confirm tool availability.- pty session start failed: check OpenCode permission rules and service-user filesystem permissions.
- Long task lacks wrapper logs/summary: rerun it through
tools/run_with_feishu_notify.sh. - Markdown fallback test: set
BRIDGE_REPLY_FORMAT=markdownand restartrca-feishu-opencode-bridge.service.
Long-running experiments must go through:
./tools/run_with_feishu_notify.sh --name <experiment_name> -- <command>Do not directly run python train.py or bash train.sh for long tasks, and do not bypass Feishu notification.