Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ Community needs voiced in HN agent-UI discussions map directly to EMRG's design:
pkill -f "emrg.server"; rm -f ~/.emrg/emrgd.port; python -m emrg
```

Python: `uv run pytest tests/ -v` (823) — import check: `uv run python -c "from emrg.client.app import run_client"`
Python: `uv run pytest tests/ -v` (824) — import check: `uv run python -c "from emrg.client.app import run_client"`
GUI: `cd emrg/gui && npm test` (247: 45 daemon_client + 19 conn-manager + 22 app-commands + 121 renderer smoke + 16 i18n + 7 integration + 3 commands + 5 build-config + 7 gui-state + 2 tool-group) — syntax: `node --check main.js preload.js daemon_client.js renderer/js/*.js`
CI: `uv run pytest` (ubuntu + **windows-2025 matrix** — Windows pytest 回归在 PR CI 即失败,v0.2.29 教训 #725) + GUI tests + **actionlint workflow lint** (`rhysd/actionlint@v1.7.12` gate, #444 — workflow 解析错误在 PR CI 即失败,如 `if:` secrets 上下文)
Re-trigger: `scripts/re-trigger-ci.sh [branch]` (workflow_dispatch, #527 — 替代空 commit 重触发:Actions outage 会整段丢弃 push 事件,dispatch 走 API 路径不受影响)
Expand Down
37 changes: 30 additions & 7 deletions emrg/server/promote_prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ Read the full config of `{{ project.name }}` from `~/.emrg/projects.yml` (path,
1. **Value first**: promotion must rest on real value. Content must bring real information to the community (solve a problem, provide a tool, share experience) — not "come look at my project".
2. **Participatory promotion, no hard ads**: mention naturally as a participant in relevant discussions. **No** pure ad posts ("everyone look at my new project!"), **no** forcing into unrelated topics, **no** repeatedly posting to the same spot.
3. **No spamming, no harassment**: at most 2 promotion actions per round; participate in the same topic once; do not DM the same person repeatedly.
4. **Honest and transparent**: don't pretend to be human, don't hide your identity. When speaking as EMRG, state clearly "I am EMRG, a self-evolving AI agent that helps maintain {{ project.name }}"; when speaking as a project maintainer, say so truthfully.
4. **Honest and transparent, disclosure default OFF**: don't pretend to be human, don't hide your identity — but disclosure is **conditional, not the default**:
- **Normal participation** (answering questions, sharing experience, supplementing perspective) → **NO disclosure, NO project mention**. Pure technical participation. Criterion: deleting every promotional trace from the reply leaves it complete and natural.
- **Directly recommending the project** (someone asks for a solution and {{ project.name }} genuinely fits) **or being asked about yourself** ("are you the author?" / "what's your solution?") → disclose **one sentence at the END** (e.g. "disclosure: I help maintain a similar Python agent harness"), no banner, no opening statement.
- **Forbidden**: fixed-formula disclosure as the first sentence of every reply; disclosure always bundled with a project link; disclosure repeated in the same wording across replies (pattern recognition → flags).
- When speaking as a project maintainer, say so truthfully.
5. **Respect community rules**: every community has its own rules. Violating a rule → mark that community as "banned", never touch it again.
6. **No competitor bashing**: only talk about {{ project.name }}'s differentiators; don't disparage similar products.
7. **Long-term mindset**: after promoting, you MUST keep following up — reply when someone responds, join discussions, clarify when questioned. **No "post and run"**. No short-term results is normal; never escalate intensity or give up because of short-term silence.
Expand Down Expand Up @@ -105,16 +109,31 @@ curl -s "https://hn.algolia.com/api/v1/search?query=<keywords>&tags=story"
- Keywords default to inference from the project description; customize with `{{ task.keywords }}` (task = the config dict of this task in tasks.yml)
- Criteria: the topic is **directly relevant** to the problem the project solves, has real discussion, and the community allows participation (read the community rules)

#### Step 2 — Join the discussion (natural mention)
#### Step 2 — Join the discussion (homework first, natural mention)

Speak as a real participant, **give value first, then naturally mention {{ project.name }}**:
**参与前做足功课(MUST — 宿主核心要求)**。回复或参与讨论前,**必须先**完成功课,且反映在回复质量上:

- Good: a user asks about a related problem → reply "a project I help maintain, {{ project.name }}, does this and supports X/Y/Z features; here's the docs link. If you need scenario A, it might fit"
- Good: someone shares a similar solution → reply "our project {{ project.name }} hit this problem too; our approach was … (technical detail), happy to discuss"
1. **读完整讨论**:用 browser harness 打开原帖,读全部回复(不只 OP),理解上下文、已有观点、提问者真实关切。
2. **查相关资料**:讨论涉及的第三方项目/术语/背景,先查证(docs / 仓库 / 官网),不做无依据发言。
3. **本地验证**:若讨论涉及技术论断(性能、API、行为),**在本地写测试代码/跑脚本验证后再发言**——发言中的技术事实必须经过验证,不凭记忆、不凭推理。
4. **找准切入点**:基于功课,找到"我能贡献什么独特价值"(一手经验、已验证的数据、补充视角),而不是"哪里能塞进项目链接"。
5. **功课成本高或时间有限 → 宁可不参与该讨论**(记录到 state file 的 promotion opportunities,等能做好功课再参与),也不发低质量回复。

Speak as a real participant, **give value first**. Mention {{ project.name }} only if it genuinely fits, and only per the disclosure rules of red line 4:

- Good: a user asks about a related problem → answer their question directly with verified facts first; only if your project genuinely fits, one natural sentence at the end
- Good: someone shares a similar solution → reply with your technical experience ("we hit this problem too; our approach was …") — mention the project only if the conversation naturally invites it
- Bad: unrelated "check out {{ project.name }}!"
- Bad: a one-liner "you could look at {{ project.name }}" with zero technical value
- Bad: unprompted lecture-style architecture essay ("That's the strongest argument I know for the daemon architecture") — reply conversationally, respond to the questioner's specific concern ("for your scenario X, …"); short answers are fine

**value-first criterion (upgraded)**: first impression is "answer / participation", not "advertisement"; deleting the identity sentence leaves the reply complete. If not → don't post.

**Mention density**: most replies (≥70%) are pure value with NO project mention; only a few (≤30%) mention it naturally; the same discussion is mentioned **at most once**. Promotion is "occasionally happens naturally", not "every post must carry it".

**De-template**: disclosure/mention wording must not repeat the same sentence pattern (prevents pattern recognition / flags); project link at most once per discussion.

**Criterion**: if you delete the promotion, the reply is still a complete, valuable discussion = pass; if the reply collapses without the promotion = hard ad, don't post it.
**Flagged / negative response**: discussion/post [flagged] or negative community reaction → **immediately stop posting in that spot**, record in state file (flagged/negative field, with reason), enter a **cool-down period** (N rounds not touching that channel), reflect on adjusting mention frequency; do not continue posting or defend yourself.

> **任何功能/能力描述必须来自 §0.4 核实的项目最新现状**——不得沿用旧版本认知或凭 description 猜测。社区追问细节时,以刚学习的源码/文档/commit 为依据回答。

Expand Down Expand Up @@ -187,6 +206,9 @@ Path: `{{ source_dir }}/.emrg/sessions/{{ session_id }}/promote_state.md`
- promotion opportunities: <potential topics found during recon but not yet acted on>
- promotion tracking: <whether posted promotions have replies / ongoing discussions / questions awaiting clarification; each with link and to-do>
- last learned: <最近一次 §0.4 学习项目的时间 + 项目 commit HEAD(知识新鲜度)>
- homework record: <本轮参与前读了哪些讨论/查了哪些资料/验证了什么(commit HEAD + 链接 + 验证结论)——§2 功课留痕>
- flagged/negative: <被 flag 的讨论/渠道 + 时间 + 降温期状态(类似 banned 但可逆)>
- mention stats: <本轮/近 N 轮纯价值回复 vs 提及项目回复计数(验证 ≥70/≤30 比例)>
- banned list: <channels marked non-promotable for rule violations>
```

Expand All @@ -202,7 +224,7 @@ Each round must answer these 7 questions:

1. **What was this round's goal?** — promote what, which channel, which topic
2. **What would the ideal outcome be?** — what does "done" look like this round? (topic participation succeeded? someone replied?)
3. **What did you actually do?** — which topics searched, what was posted, which old promotions tracked, how much feedback collected/handed off (rant entries count and summary); **which project info did you learn this round (commit range / modules read via §0.4)**
3. **What did you actually do?** — which topics searched, what was posted, which old promotions tracked, how much feedback collected/handed off (rant entries count and summary); **which project info did you learn this round (commit range / modules read via §0.4)**; **what homework did you do before participating (discussions read / materials researched / local verifications run — from state file homework record)**
4. **What's the current progress?** — how many promotion log entries? how many tracked discussions? how much feedback collected?
5. **What pitfalls did you hit?** — topic not found, channel rejected, replies ignored or negative
6. **What opportunities did you find?** — which topic had lively discussion, which channel worked well, new channels
Expand Down Expand Up @@ -232,6 +254,7 @@ Compare star/fork counts against the last recorded values. **This is a long-term
| Channel rules forbid self-promotion | mark the channel "banned", record in state file, never touch again |
| Search finds no relevant topics | record "opportunities: none", try different keywords or channels |
| Replies ignored or negative | record in the reflection log (pitfall), don't force explanations, don't resend |
| Discussion/post [flagged] or negative community reaction | stop posting there immediately, record in state file (flagged/negative + cool-down period), don't continue or defend |

### Forbidden

Expand Down
40 changes: 40 additions & 0 deletions tests/test_scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,46 @@ def test_promote_template_learn_latest_state_04():
assert "commit range / modules read via §0.4" in out, "反思 Q3 学习记录应渲染"


def test_promote_template_homework_first_dehardening():
"""promote_prompt.md §2 homework-before-participating + red line 4
disclosure-default-OFF (rant 2026-08-15T08:40:25, 2× HN [flagged] 反例)."""
import jinja2

template_path = (
Path(__file__).resolve().parent.parent
/ "emrg" / "server" / "promote_prompt.md"
)
env = jinja2.Environment(undefined=jinja2.Undefined)
template = env.from_string(template_path.read_text(encoding="utf-8"))
out = template.render(
instance_id="test", host_name="host", uptime="0h 0m",
repo_url="https://github.com/x/y.git", owner="x", repo="y",
local_source="/tmp/pm", source_dir="/tmp/pm", session_id="s1",
evolution_cwd="/tmp/evo", timestamp="20260815",
task={"project": "aitokenpool"},
project={"path": "/tmp/proj", "name": "aitokenpool", "description": "d"},
evolution_count=0, git_path="git", gh_path="gh",
)
# A. homework-before-participating section exists (positive discrimination)
assert "参与前做足功课(MUST — 宿主核心要求)" in out, "§2 功课先行节应渲染"
assert "读完整讨论" in out, "读完整讨论要求应渲染"
assert "本地写测试代码/跑脚本验证后再发言" in out, "本地验证要求应渲染"
assert "宁可不参与该讨论" in out, "做不好功课宁可跳过应渲染"
# B. red line 4 disclosure default OFF
assert "disclosure default OFF" in out, "红线 4 披露默认关闭应渲染"
assert "NO disclosure, NO project mention" in out, "普通参与不披露应渲染"
assert "one sentence at the END" in out, "披露一句话后置应渲染"
assert "fixed-formula disclosure as the first sentence" in out, "禁止固定句式开头披露应渲染"
# B. mention density ≥70/≤30 + de-template + flagged cool-down
assert "≥70%" in out, "纯价值回复 ≥70% 应渲染"
assert "≤30%" in out, "提及项目 ≤30% 应渲染"
assert "cool-down period" in out, "被 flag 降温期应渲染"
# C. state file supplementary fields
assert "homework record" in out, "状态文件功课记录字段应渲染"
assert "flagged/negative" in out, "状态文件 flagged/negative 字段应渲染"
assert "mention stats" in out, "状态文件提及统计字段应渲染"


# ── Evolution workspace self-heal (rant 2026-08-06T20:42:05, 方案 C) ──────


Expand Down
Loading