feat(harness): add kimi crewmate harness adapter#89
Open
aintnorest wants to merge 6 commits into
Open
Conversation
517426a to
4420d7f
Compare
Add kimi-code 0.19.2 as a verified harness adapter (claude/codex/opencode/pi/kimi). Mechanics (bin/): - fm-spawn.sh: `kimi --yolo` launch template; per-task KIMI_CODE_HOME at state/<id>.kimi-home that symlinks ~/.kimi-code (sharing the captain's login) except config.toml, which is copied and gets a merged Stop hook; brief injected into the interactive composer because --prompt conflicts with --yolo. - fm-kimi-merge-hook.sh: safely append the turn-end Stop hook to the copied config. - fm-harness.sh: detect kimi by command name in process ancestry (no env marker). - fm-teardown.sh: remove state/<id>.kimi-home (including secondmate children). - fm-watch.sh / fm-tmux-lib.sh: kimi busy signatures (thinking.../working...). - fm-tmux-lib.sh: fm_tmux_inject_brief + fm_tmux_composer_box_state. Brief submission is verified against the whole composer box, not the single cursor row, because kimi parks the cursor on a blank box row; Enter is retried through pi-tui cold start so a dropped first Enter no longer silently drops the brief. Knowledge: AGENTS.md section 4 kimi table; README prerequisites. Verified live (kimi-code 0.19.2): launch, login sharing, composer brief injection and submission, the Stop turn-end hook, and teardown cleanup.
…ptain config via symlink
…on and delete on paste
4420d7f to
e83f9f6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What Changed
kimiharness adapter:fm-harness.shdetects kimi by process-ancestry command match,fm-spawn.shlauncheskimi --yolowith a per-taskKIMI_CODE_HOME(symlinking~/.kimi-codeexceptconfig.toml, which is copied by content so the captain's config is never mutated), andfm-teardown.shremoves the per-taskstate/<id>.kimi-home.fm-tmux-lib.shto inject the brief into kimi's interactive composer via a per-spawn tmux buffer (deleted on paste), retrying until the composer clears and accepting a busy pane (thinking.../working...) as submit confirmation; addedbin/fm-kimi-merge-hook.shto idempotently append the Stop turn-end hook to a copiedconfig.toml, and broadened the watcher busy regex.AGENTS.md,README.md, and theharness-adapters/afkskills, and added test suites covering injection, spawn, merge-hook, and teardown behavior.Risk Assessment
✅ Low: Additive, well-bounded new harness adapter that leaves existing harness paths untouched, the prior-round injection concern is fixed, and the only cross-cutting effect (the shared busy regex) is footer-scoped to limit false negatives.
Testing
Ran the four kimi-specific behavior suites and the rest of the non-e2e suite — all pass. The two heavy e2e/daemon/watcher suites were skipped because the local macOS environment lacks
timeoutand they block; they are unrelated to the kimi adapter. Beyond the unit suites I produced an end-to-end transcript driving the actual adapter scripts to show the captain-visible behavior: kimi harness detection, the Stop turn-end hook merged into a genuine config.toml, idempotent re-merge (no duplicate hook), and the safety refusal that protects a config with a bare [hooks] table. This is shell/CLI tooling with no user-facing UI, so no screenshot/visual artifact applies; the CLI transcript is the appropriate product-level evidence.Evidence: kimi adapter end-to-end transcript
### 3. Stop turn-end hook merged into a real kimi config.toml --- after merge --- model = "kimi-code" [provider] name = "moonshot" [[hooks]] event = "Stop" command = "touch '/path/to/state/fix-login-k3.turn-ended'" ### 4. Idempotency: Stop-hook count: 1 ### 5. Safety: error: bad.toml contains a bare [hooks] table; cannot merge Stop hook (exit 1)Pipeline
Updates from git push no-mistakes
⏭️ **intent** - skipped
✅ No issues found.
🔧 **Rebase** - 1 issue found → auto-fixed ✅
README.md- merge conflict rebasing onto origin/main🔧 Fix applied.
✅ Re-checked - no issues remain.
bin/fm-tmux-lib.sh:297- fm_tmux_inject_brief's submit-verification loop (bin/fm-tmux-lib.sh) only accepts a composer box state of 'empty' as confirmation the brief was submitted. If kimi replaces or hides the composer prompt row with a busy/processing view after Enter, fm_tmux_composer_box_state returns 'unknown', the loop exhausts its retries (~15s) and returns 1, which fm-spawn.sh:479 turns into 'exit 1' and aborts the spawn even though the brief was successfully delivered. Consider also treating a busy signature (FM_TMUX_BUSY_REGEX) as confirmation that the brief left the composer.bin/fm-spawn.sh:419- The per-task kimi home (bin/fm-spawn.sh:413-421) symlinks every entry of the captain's real ~/.kimi-code except config.toml, including the sessions directory and credentials. All kimi crewmates therefore share the captain's session store; teardown's 'rm -rf $ID.kimi-home' only removes the symlinks, so crewmate sessions accumulate in the captain's real directory. Acceptable as long as concurrent crewmate sessions don't collide on shared session files.🔧 Fix: accept busy pane as kimi brief submit confirmation
1 info still open:
bin/fm-watch.sh:80- The default BUSY_REGEX (also FM_TMUX_BUSY_REGEX_DEFAULT in fm-tmux-lib.sh:42) is global across all harnesses, and now adds the generic words 'thinking...' and 'working...'. Because matching is case-insensitive, 'working...' is fully redundant with the existing 'Working...', and 'thinking...' is broad enough that a stalled non-kimi crewmate whose last 6 non-blank lines happen to end with 'thinking...' would be treated as busy and never flagged stale. The footer-only scope (last 6 non-blank lines) limits this in practice, and anchoring the kimi spinner with its leading braille glyph would tighten it further, but the current behavior is an acceptable, documented tradeoff.✅ **Test** - passed
✅ No issues found.
bash tests/fm-kimi-inject.test.sh(single/multi-line brief injection, retry-until-composer-clears, busy-pane-as-submit, timeout)bash tests/fm-kimi-spawn.test.sh(launch templatekimi --yolo, per-task KIMI_CODE_HOME, copied config carries Stop hook, fail-fast on missing ~/.kimi-code)bash tests/fm-kimi-merge-hook.test.sh(append/idempotent/bare-[hooks]-error/array-of-tables/newline cases)bash tests/fm-kimi-teardown.test.sh(removes state/<id>.kimi-home, nested secondmate child)Full non-e2e suite: fm-bootstrap, fm-composer-ghost, fm-secondmate-safety, fm-spawn-batch, fm-teardown, fm-update, fm-wake-queue — all passManual e2e transcript:bin/fm-harness.sh crewresolving kimi override, andbin/fm-kimi-merge-hook.shproducing/refusing real config.toml content✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.