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
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ HarnessKit manages **all five extension types** from a unified interface — **S
| **Windsurf** | ✓ | ✓ | — | ✓ | ✓ |
| **OpenCode** | ✓ | ✓ | ✓ | — | ✓ |
| **Hermes** | ✓ | ✓ | ✓ | ✓ | ✓ |
| **Kiro** | ✓ | ✓ | — | ✓ | ✓ |

<small><i>* "—" indicates the agent currently does not support this extension type.</i></small>

Expand All @@ -86,7 +87,7 @@ HarnessKit manages **all five extension types** from a unified interface — **S

### 🤖 Agent Configs, Memory & Rules

HarnessKit manages every agent's **Configs**, **Memory**, **Rules**, **Subagents**, and **Ignore** files from one place. Currently supporting **9 agents**: **Claude Code**, **Codex**, **Gemini CLI**, **Cursor**, **Antigravity**, **Copilot**, **Windsurf**, **OpenCode**, and **Hermes**.
HarnessKit manages every agent's **Configs**, **Memory**, **Rules**, **Subagents**, and **Ignore** files from one place. Currently supporting **10 agents**: **Claude Code**, **Codex**, **Gemini CLI**, **Cursor**, **Antigravity**, **Copilot**, **Windsurf**, **OpenCode**, **Hermes**, and **Kiro**.

- **Config file tracking** — Automatically discovers every agent's config files — both global and per-project. Add your project directories or custom paths and HarnessKit picks them up alongside the global ones.
- **Per-agent dashboard** — Each agent gets its own page with all files organized by category, showing scope, path, file size, and a summary of installed extensions. Expand any file to preview its content right in the app.
Expand Down Expand Up @@ -174,7 +175,7 @@ HarnessKit ships a standalone command-line interface (`hk`) for terminal-first w

```shell
$ hk status
Agents 9 detected (claude · codex · gemini · cursor · antigravity · copilot · windsurf · opencode · hermes)
Agents 10 detected (claude · codex · gemini · cursor · antigravity · copilot · windsurf · opencode · hermes · kiro)
Extensions 136 total (124 skills · 2 mcp · 8 plugins · 1 hooks · 1 clis)

$ hk list --kind skill --agent claude # filter by type and agent
Expand Down Expand Up @@ -366,7 +367,7 @@ See [CLI Support](#%EF%B8%8F-cli-support) above for the full list of commands.

## Roadmap

- 🤖 **More Agents** — Hermes-agent, OpenClaw, and more
- 🤖 **More Agents** — OpenClaw and more
- ⌨️ **CLI Enhancements** — More commands and richer functionality for `hk`

---
Expand Down
7 changes: 4 additions & 3 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ HarnessKit 通过统一界面管理 **全部五种扩展类型** —— **Skill*
| **Windsurf** | ✓ | ✓ | — | ✓ | ✓ |
| **OpenCode** | ✓ | ✓ | ✓ | — | ✓ |
| **Hermes** | ✓ | ✓ | ✓ | ✓ | ✓ |
| **Kiro** | ✓ | ✓ | — | ✓ | ✓ |

<small><i>* "—" 表示该 Agent 目前不支持此扩展类型。</i></small>

Expand All @@ -86,7 +87,7 @@ HarnessKit 通过统一界面管理 **全部五种扩展类型** —— **Skill*

### 🤖 Agent 配置、记忆与规则

HarnessKit 统一管理每个 Agent 的 **配置**、**记忆**、**规则**、**子 Agent** 与 **忽略**(Ignore)文件。目前支持 **9 个 Agent**:**Claude Code**、**Codex**、**Gemini CLI**、**Cursor**、**Antigravity**、**Copilot**、**Windsurf**、**OpenCode** 与 **Hermes**。
HarnessKit 统一管理每个 Agent 的 **配置**、**记忆**、**规则**、**子 Agent** 与 **忽略**(Ignore)文件。目前支持 **10 个 Agent**:**Claude Code**、**Codex**、**Gemini CLI**、**Cursor**、**Antigravity**、**Copilot**、**Windsurf**、**OpenCode**、**Hermes** 与 **Kiro**。

- **配置文件跟踪** —— 自动发现每个 Agent 的全局与项目级配置文件。添加项目目录或自定义路径后,HarnessKit 会将它们与全局配置一同纳入管理。
- **Agent 专属面板** —— 每个 Agent 拥有独立页面,文件按类别组织,列出范围、路径、文件大小以及已安装扩展的概览。展开任意文件即可在应用内预览。
Expand Down Expand Up @@ -174,7 +175,7 @@ HarnessKit 提供独立命令行工具(`hk`),面向偏好终端的工作

```shell
$ hk status
Agents 9 detected (claude · codex · gemini · cursor · antigravity · copilot · windsurf · opencode · hermes)
Agents 10 detected (claude · codex · gemini · cursor · antigravity · copilot · windsurf · opencode · hermes · kiro)
Extensions 136 total (124 skills · 2 mcp · 8 plugins · 1 hooks · 1 clis)

$ hk list --kind skill --agent claude # 按类型与 Agent 筛选
Expand Down Expand Up @@ -366,7 +367,7 @@ HarnessKit Web UI [my-host] running at http://127.0.0.1:7070/?token=a1b2c3…

## 未来计划

- 🤖 **更多 Agent** —— Hermes-agent、OpenClaw 等
- 🤖 **更多 Agent** —— OpenClaw 等
- ⌨️ **CLI 增强** —— 为 `hk` 添加更多命令与更丰富的功能

---
Expand Down
1 change: 1 addition & 0 deletions crates/hk-core/src/adapter/claude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ impl AgentAdapter for ClaudeAdapter {
event: event.clone(),
matcher: matcher.clone(),
command,
enabled: true,
});
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/hk-core/src/adapter/codex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ impl AgentAdapter for CodexAdapter {
event: event.clone(),
matcher: matcher.clone(),
command,
enabled: true,
});
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/hk-core/src/adapter/copilot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ impl AgentAdapter for CopilotAdapter {
event: event.clone(),
matcher: None,
command: cmd_str.to_string(),
enabled: true,
});
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/hk-core/src/adapter/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ impl AgentAdapter for CursorAdapter {
event: event.clone(),
matcher: None,
command: cmd.to_string(),
enabled: true,
});
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/hk-core/src/adapter/gemini.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ impl AgentAdapter for GeminiAdapter {
event: event.clone(),
matcher: matcher.clone(),
command,
enabled: true,
});
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/hk-core/src/adapter/hermes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ impl AgentAdapter for HermesAdapter {
event: event.to_string(),
matcher,
command: command.to_string(),
enabled: true,
});
}
}
Expand Down
85 changes: 78 additions & 7 deletions crates/hk-core/src/adapter/hook_events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
//! - Copilot: https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/use-hooks
//! - Windsurf: https://docs.windsurf.com/windsurf/cascade/hooks
//! - Antigravity: no hook support — use rules instead: https://antigravity.google/docs/rules-workflows
//! - Kiro IDE: https://kiro.dev/docs/hooks/

// Canonical event names (Claude's convention) used as the internal lingua franca.
const CANONICAL_EVENTS: &[&str] = &[
Expand Down Expand Up @@ -337,6 +338,52 @@ const HERMES_EVENTS: &[EventMapping] = &[
},
];

/// Kiro IDE Agent Hook mappings.
/// Reference: https://kiro.dev/docs/hooks/
const KIRO_EVENTS: &[EventMapping] = &[
EventMapping {
canonical: "SessionStart",
agent: "SessionStart",
},
EventMapping {
canonical: "Stop",
agent: "Stop",
},
EventMapping {
canonical: "PreToolUse",
agent: "PreToolUse",
},
EventMapping {
canonical: "PostToolUse",
agent: "PostToolUse",
},
EventMapping {
canonical: "UserPromptSubmit",
agent: "UserPromptSubmit",
},
// Kiro-specific triggers.
EventMapping {
canonical: "PreTaskExec",
agent: "PreTaskExec",
},
EventMapping {
canonical: "PostTaskExec",
agent: "PostTaskExec",
},
EventMapping {
canonical: "PostFileCreate",
agent: "PostFileCreate",
},
EventMapping {
canonical: "PostFileSave",
agent: "PostFileSave",
},
EventMapping {
canonical: "PostFileDelete",
agent: "PostFileDelete",
},
];

/// Translate an event name from any agent's convention to the target agent's convention.
/// Returns None if the event has no equivalent in the target agent.
fn translate(
Expand Down Expand Up @@ -371,6 +418,7 @@ pub fn to_claude(event: &str) -> Option<String> {
.or_else(|| translate(event, COPILOT_EVENTS, CLAUDE_EVENTS))
.or_else(|| translate(event, WINDSURF_EVENTS, CLAUDE_EVENTS))
.or_else(|| translate(event, HERMES_EVENTS, CLAUDE_EVENTS))
.or_else(|| translate(event, KIRO_EVENTS, CLAUDE_EVENTS))
}

/// Translate an event name to Gemini convention.
Expand All @@ -381,6 +429,7 @@ pub fn to_gemini(event: &str) -> Option<String> {
.or_else(|| translate(event, COPILOT_EVENTS, GEMINI_EVENTS))
.or_else(|| translate(event, WINDSURF_EVENTS, GEMINI_EVENTS))
.or_else(|| translate(event, HERMES_EVENTS, GEMINI_EVENTS))
.or_else(|| translate(event, KIRO_EVENTS, GEMINI_EVENTS))
}

/// Translate an event name to Cursor convention.
Expand All @@ -391,6 +440,7 @@ pub fn to_cursor(event: &str) -> Option<String> {
.or_else(|| translate(event, COPILOT_EVENTS, CURSOR_EVENTS))
.or_else(|| translate(event, WINDSURF_EVENTS, CURSOR_EVENTS))
.or_else(|| translate(event, HERMES_EVENTS, CURSOR_EVENTS))
.or_else(|| translate(event, KIRO_EVENTS, CURSOR_EVENTS))
}

/// Translate an event name to Copilot convention.
Expand All @@ -401,6 +451,7 @@ pub fn to_copilot(event: &str) -> Option<String> {
.or_else(|| translate(event, CURSOR_EVENTS, COPILOT_EVENTS))
.or_else(|| translate(event, WINDSURF_EVENTS, COPILOT_EVENTS))
.or_else(|| translate(event, HERMES_EVENTS, COPILOT_EVENTS))
.or_else(|| translate(event, KIRO_EVENTS, COPILOT_EVENTS))
}

/// Translate an event name to Windsurf convention.
Expand All @@ -411,6 +462,7 @@ pub fn to_windsurf(event: &str) -> Option<String> {
.or_else(|| translate(event, CURSOR_EVENTS, WINDSURF_EVENTS))
.or_else(|| translate(event, COPILOT_EVENTS, WINDSURF_EVENTS))
.or_else(|| translate(event, HERMES_EVENTS, WINDSURF_EVENTS))
.or_else(|| translate(event, KIRO_EVENTS, WINDSURF_EVENTS))
}

/// Translate an event name to Hermes convention.
Expand All @@ -421,6 +473,18 @@ pub fn to_hermes(event: &str) -> Option<String> {
.or_else(|| translate(event, CURSOR_EVENTS, HERMES_EVENTS))
.or_else(|| translate(event, COPILOT_EVENTS, HERMES_EVENTS))
.or_else(|| translate(event, WINDSURF_EVENTS, HERMES_EVENTS))
.or_else(|| translate(event, KIRO_EVENTS, HERMES_EVENTS))
}

/// Translate an event name to Kiro IDE convention.
pub fn to_kiro(event: &str) -> Option<String> {
translate(event, KIRO_EVENTS, KIRO_EVENTS)
.or_else(|| translate(event, CLAUDE_EVENTS, KIRO_EVENTS))
.or_else(|| translate(event, GEMINI_EVENTS, KIRO_EVENTS))
.or_else(|| translate(event, CURSOR_EVENTS, KIRO_EVENTS))
.or_else(|| translate(event, COPILOT_EVENTS, KIRO_EVENTS))
.or_else(|| translate(event, WINDSURF_EVENTS, KIRO_EVENTS))
.or_else(|| translate(event, HERMES_EVENTS, KIRO_EVENTS))
}

#[cfg(test)]
Expand Down Expand Up @@ -485,6 +549,15 @@ mod tests {
assert_eq!(to_windsurf("PreToolUse"), None);
}

#[test]
fn kiro_events_translate_and_passthrough() {
assert_eq!(to_kiro("PostFileSave"), Some("PostFileSave".into()));
assert_eq!(to_kiro("PreTaskExec"), Some("PreTaskExec".into()));
assert_eq!(to_kiro("BeforeTool"), Some("PreToolUse".into()));
assert_eq!(to_claude("PostFileSave"), None);
assert_eq!(to_kiro("pre_run_command"), None);
}

/// The 10 Windsurf-specific events have no canonical equivalent;
/// they must passthrough when the target agent is Windsurf itself.
#[test]
Expand Down Expand Up @@ -532,12 +605,7 @@ mod tests {
assert_eq!(to_claude(event), None, "to_claude leaked for '{}'", event);
assert_eq!(to_gemini(event), None, "to_gemini leaked for '{}'", event);
assert_eq!(to_cursor(event), None, "to_cursor leaked for '{}'", event);
assert_eq!(
to_copilot(event),
None,
"to_copilot leaked for '{}'",
event
);
assert_eq!(to_copilot(event), None, "to_copilot leaked for '{}'", event);
}
}

Expand Down Expand Up @@ -565,7 +633,10 @@ mod tests {
// canonical → hermes
assert_eq!(to_hermes("PreToolUse").as_deref(), Some("pre_tool_call"));
assert_eq!(to_hermes("PostToolUse").as_deref(), Some("post_tool_call"));
assert_eq!(to_hermes("SessionStart").as_deref(), Some("on_session_start"));
assert_eq!(
to_hermes("SessionStart").as_deref(),
Some("on_session_start")
);
assert_eq!(to_hermes("SubagentStop").as_deref(), Some("subagent_stop"));
// hermes native passthrough
assert_eq!(to_hermes("pre_tool_call").as_deref(), Some("pre_tool_call"));
Expand Down
Loading
Loading