use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use serde_json::Value;
use super::normalize;
use super::{ActionCommand, ActionEnvelope, ActionLlmParse, ActionMcpCall, ActionToken};
use crate::zone_eval::effect::path::PathEnv;
use crate::zone_eval::effect::shell;
use crate::zone_eval::facts::FactSet;
use crate::zone_eval::types::SimpleCommand;
pub const MAX_ACTION_BYTES: usize = 16 * 1024;
const HARNESS_PROVIDERS: &[(&str, &str)] = &[
("claude-code", "anthropic"),
("codex-cli", "openai"),
("cursor", "cursor"),
("cline", "cline"),
("opencode", "opencode"),
];
const TOOL_NAMES: &[(&str, &str)] = &[
("Bash", "bash"),
("Shell", "bash"),
("execute_command", "bash"),
("run_commands", "bash"),
("bash", "bash"),
("shell", "bash"),
("Read", "read"),
("read_file", "read"),
("read_files", "read"),
("read", "read"),
("Edit", "edit"),
("replace_in_file", "edit"),
("editor", "edit"),
("edit", "edit"),
("apply_patch", "edit"),
("Write", "write"),
("write_to_file", "write"),
("write", "write"),
("Grep", "search"),
("Glob", "search"),
("search_files", "search"),
("search_codebase", "search"),
("grep", "search"),
("glob", "search"),
("WebFetch", "web"),
("WebSearch", "web"),
("web_fetch", "web"),
("fetch_web_content", "web"),
("webfetch", "web"),
("websearch", "web"),
("Agent", "agent"),
("Task", "agent"),
("spawn_agent", "agent"),
("new_task", "agent"),
("task", "agent"),
];
const TOOL_INPUT_POINTER: &str = "/data/tool_input";
static ENABLED: AtomicBool = AtomicBool::new(false);
static ERRORS: AtomicU64 = AtomicU64::new(0);
pub fn set_enabled(on: bool) {
ENABLED.store(on, Ordering::Relaxed);
}
pub fn enabled() -> bool {
ENABLED.load(Ordering::Relaxed)
}
pub fn note_error() {
ERRORS.fetch_add(1, Ordering::Relaxed);
}
pub fn errors() -> u64 {
ERRORS.load(Ordering::Relaxed)
}
pub fn to_action(envelope: &Value) -> Option<Value> {
let data = envelope.get("data")?;
let common_tool = text(data, "tool_name")?;
let raw = data.get("raw_agent_payload");
let native_call = normalize::tool_call_of(raw.unwrap_or(data), None);
let native = native_call
.as_ref()
.map_or(common_tool, |call| call.native.as_str());
let mcp = mcp_call(native, common_tool, data);
let tool_name = match &mcp {
Some(call) => format!("{}.{}", call.server, call.tool),
None => TOOL_NAMES
.iter()
.find(|(name, _)| *name == native)
.map_or_else(|| native.to_lowercase(), |(_, common)| common.to_string()),
};
let payload_llm_cmd = (tool_name == "bash")
.then(|| {
let raw_input = native_call.as_ref().and_then(|call| call.input.as_ref());
commands(raw_input, data.get("tool_input"))
})
.flatten();
let payload_raw = ["raw_agent_payload", "tool_input"]
.into_iter()
.find(|key| data.get(key).is_some())
.map(|key| format!("/data/{key}"));
let source = envelope.get("source")?.as_str()?;
let action = ActionEnvelope {
harness_provider: harness_provider(source),
harness_name: source.to_string(),
session_id: text(data, "session_id").map(str::to_string),
cwd: text(data, "cwd").map(str::to_string),
timestamp: unix_ms(envelope.get("time")?.as_str()?)?,
action_id: normalize::tool_use_id_of(raw.unwrap_or(data))
.or_else(|| envelope.get("id")?.as_str())?
.to_string(),
action_type: if mcp.is_some() { "mcp" } else { "tool" }.to_string(),
tool_name: Some(tool_name),
payload_raw,
payload_llm_parse: None,
payload_llm_mcp: mcp,
payload_llm_cmd,
};
capped(action)
}
pub fn llm_action(
source: &str,
session_id: Option<&str>,
occurred_at: &str,
event_id: &str,
parse: ActionLlmParse,
) -> Value {
let action = ActionEnvelope {
harness_provider: harness_provider(source),
harness_name: source.to_string(),
session_id: session_id.map(str::to_string),
cwd: None,
timestamp: unix_ms(occurred_at).unwrap_or_else(|| chrono::Utc::now().timestamp_millis()),
action_id: event_id.to_string(),
action_type: "llm".to_string(),
tool_name: None,
payload_raw: None,
payload_llm_parse: Some(parse),
payload_llm_mcp: None,
payload_llm_cmd: None,
};
serde_json::to_value(action).unwrap_or_default()
}
fn harness_provider(source: &str) -> Option<String> {
HARNESS_PROVIDERS
.iter()
.find(|(name, _)| *name == source)
.map(|(_, provider)| provider.to_string())
}
fn text<'a>(data: &'a Value, key: &str) -> Option<&'a str> {
data.get(key)?.as_str().filter(|s| !s.is_empty())
}
fn unix_ms(time: &str) -> Option<i64> {
chrono::DateTime::parse_from_rfc3339(time)
.ok()
.map(|t| t.timestamp_millis())
}
fn mcp_call(native: &str, common: &str, data: &Value) -> Option<ActionMcpCall> {
let call = |server: &str, tool: &str| ActionMcpCall {
server: server.to_string(),
tool: tool.to_string(),
arguments: TOOL_INPUT_POINTER.to_string(),
};
for name in [common, native] {
if let Some((server, tool)) = name.strip_prefix("mcp__").and_then(|n| n.split_once("__")) {
return Some(call(server, tool));
}
}
if let Some(tool) = native.strip_prefix("MCP:") {
return Some(call("unknown", tool));
}
if native == "use_mcp_tool" {
let input = data.get("tool_input").unwrap_or(&Value::Null);
let arg = |key| text(input, key).unwrap_or("unknown");
return Some(call(arg("server_name"), arg("tool_name")));
}
None
}
fn commands(raw_input: Option<&Value>, common_input: Option<&Value>) -> Option<Vec<ActionCommand>> {
let lines: Vec<&str> = match raw_input
.and_then(|input| input.get("commands"))
.and_then(Value::as_array)
{
Some(list) => list
.iter()
.filter_map(|entry| entry.as_str().or_else(|| entry.get("command")?.as_str()))
.collect(),
None => vec![common_input?.get("command")?.as_str()?],
};
let mut simple = Vec::new();
for line in lines {
let cls = shell::classify_command(line, &FactSet::default(), &PathEnv::default());
if cls.simple.is_empty() {
return None;
}
simple.extend(fold_wrappers(&cls.simple).into_iter().map(command_of));
}
if simple.is_empty() {
return None;
}
let chained = simple.len() > 1;
for command in &mut simple {
command.is_chained = chained;
}
Some(simple)
}
fn fold_wrappers(simple: &[SimpleCommand]) -> Vec<&[SimpleCommand]> {
let wraps = |outer: &SimpleCommand, inner: &SimpleCommand| {
let n = inner.raw_argv.len();
let program = outer.program.as_str();
(program == "docker"
|| [
shell::WRAPPERS,
shell::ENV_RUNNERS,
shell::RECURSING_ESCALATORS,
]
.iter()
.any(|table| table.contains(&program)))
&& outer.raw_argv.len() > n
&& outer.raw_argv.ends_with(&inner.raw_argv)
&& shell::normalise(&shell::unquote(
&outer.raw_argv[outer.raw_argv.len() - n - 1],
)) == inner.program
};
let mut runs = Vec::new();
let mut i = 0;
while i < simple.len() {
let mut j = i;
while j + 1 < simple.len() && wraps(&simple[j], &simple[j + 1]) {
j += 1;
}
runs.push(&simple[i..=j]);
i = j + 1;
}
runs
}
fn command_of(run: &[SimpleCommand]) -> ActionCommand {
let token = |t: &str, v: &str, target: Option<&str>| ActionToken {
t: t.to_string(),
v: v.to_string(),
target: target.map(str::to_string),
};
let sc = &run[run.len() - 1];
let part = run
.iter()
.map(|c| c.raw.as_str())
.max_by_key(|raw| raw.len());
let mut words = shell::tokenise(part.unwrap_or_default()).unwrap_or_default();
let redirects = run.iter().find(|c| !c.redirects.is_empty()).unwrap_or(sc);
for (op, target) in &redirects.raw_redirects {
if let Some(at) = words
.windows(2)
.position(|pair| pair[0] == *op && pair[1] == *target)
{
words.drain(at..at + 2);
}
}
let own = 1 + sc.raw_argv.len();
let prefix = &words[..words.len().saturating_sub(own)];
let mut tokens: Vec<ActionToken> = prefix
.iter()
.map(|word| {
let kind = if is_assignment(word) {
"assignment"
} else {
"wrapper"
};
token(kind, &shell::unquote(word), None)
})
.collect();
if !sc.program.is_empty() {
tokens.push(token("program", &sc.program, None));
}
tokens.extend(sc.argv.iter().map(|arg| {
let kind = if arg.starts_with('-') { "flag" } else { "arg" };
token(kind, arg, None)
}));
tokens.extend(
redirects
.redirects
.iter()
.map(|(op, target)| token("redirect", op, Some(target))),
);
ActionCommand {
cmd: sc.program.clone(),
argv: sc.argv.clone(),
is_chained: false,
tokens,
}
}
fn is_assignment(word: &str) -> bool {
word.split_once('=').is_some_and(|(name, _)| {
!name.is_empty() && name.chars().all(|c| c.is_alphanumeric() || c == '_')
})
}
fn capped(mut action: ActionEnvelope) -> Option<Value> {
let fits = |action: &ActionEnvelope| {
serde_json::to_vec(action).is_ok_and(|bytes| bytes.len() <= MAX_ACTION_BYTES)
};
if !fits(&action) {
for command in action.payload_llm_cmd.iter_mut().flatten() {
command.tokens.clear();
}
}
if !fits(&action) {
action.payload_llm_cmd = None;
}
fits(&action).then(|| serde_json::to_value(&action).ok())?
}
#[cfg(test)]
mod tests {
use serde_json::{json, Value};
use super::*;
use crate::hooks::bindings::{aliases_for, binding_id};
const TIME: &str = "2026-10-14T09:12:15.123Z";
const TIME_MS: i64 = 1_791_969_135_123;
const EVENT_ID: &str = "evt_019e2a7c-3f10-7c4e-9a51-6b0f2d8e4a17";
fn hook_envelope(source: &str, event_type: &str, native: Value) -> Value {
let binding = binding_id(source, false);
let data =
super::normalize::to_common(&native, aliases_for(source), &binding).unwrap_or(native);
json!({
"specversion": "1.0",
"id": EVENT_ID,
"source": source,
"type": event_type,
"time": TIME,
"datacontenttype": "application/json",
"data": data,
})
}
fn action_of(source: &str, native: Value) -> Value {
let action = to_action(&hook_envelope(source, "pre_tool_use", native)).expect("an action");
assert_valid(&action);
action
}
fn assert_valid(action: &Value) {
let schema: Value =
serde_json::from_str(include_str!("../../../schemas/action-envelope.schema.json"))
.expect("schema is JSON");
let validator = jsonschema::validator_for(&schema).expect("schema compiles");
let errors: Vec<String> = validator
.iter_errors(action)
.map(|e| e.to_string())
.collect();
assert!(errors.is_empty(), "{action}: {errors:?}");
}
fn claude(tool: &str, input: Value) -> Value {
json!({
"session_id": "8f2c1e4a-6b1d-4c7e-9f3a-2d5b7c9e1f04",
"transcript_path": "/Users/dev/.claude/projects/-repo/8f2c1e4a.jsonl",
"cwd": "/repo",
"permission_mode": "default",
"hook_event_name": "PreToolUse",
"tool_name": tool,
"tool_input": input,
"tool_use_id": "toolu_01HbQ4tWm8XJk2vF9pL3sR7n",
})
}
fn codex(tool: &str, input: Value) -> Value {
json!({
"session_id": "s-41",
"transcript_path": "/home/dev/.codex/sessions/2026/10/14/rollout-s-41.jsonl",
"cwd": "/repo",
"hook_event_name": "PreToolUse",
"model": "gpt-5.2-codex",
"turn_id": "turn-7",
"tool_name": tool,
"tool_input": input,
"tool_use_id": "call_7Q2",
})
}
fn cline_classic(tool: &str, parameters: Value) -> Value {
json!({
"clineVersion": "3.38.1",
"hookName": "PreToolUse",
"timestamp": "1791969135123",
"taskId": "1791969100000",
"workspaceRoots": ["/Users/dev/work/app"],
"userId": "u-1",
"preToolUse": {"toolName": tool, "parameters": parameters},
})
}
fn cmd(command: &str) -> Value {
action_of("claude-code", claude("Bash", json!({"command": command})))["payload_llm_cmd"]
.clone()
}
fn programs(cmds: &Value) -> Vec<&str> {
cmds.as_array()
.expect("commands")
.iter()
.map(|c| c["cmd"].as_str().unwrap())
.collect()
}
#[test]
fn codex_bash_is_the_spec_example() {
let action = action_of(
"codex-cli",
codex(
"Bash",
json!({"command": "npm test && git push origin develop"}),
),
);
assert_eq!(
action,
json!({
"harness_provider": "openai",
"harness_name": "codex-cli",
"session_id": "s-41",
"cwd": "/repo",
"timestamp": TIME_MS,
"action_id": "call_7Q2",
"action_type": "tool",
"tool_name": "bash",
"payload_raw": "/data/tool_input",
"payload_llm_parse": null,
"payload_llm_mcp": null,
"payload_llm_cmd": [
{"cmd": "npm", "argv": ["test"], "is_chained": true,
"tokens": [{"t": "program", "v": "npm"}, {"t": "arg", "v": "test"}]},
{"cmd": "git", "argv": ["push", "origin", "develop"], "is_chained": true,
"tokens": [{"t": "program", "v": "git"}, {"t": "arg", "v": "push"},
{"t": "arg", "v": "origin"}, {"t": "arg", "v": "develop"}]}
]
})
);
}
#[test]
fn codex_apply_patch_is_an_edit_keyed_on_its_native_name() {
let action = action_of(
"codex-cli",
codex(
"apply_patch",
json!({"input": "*** Begin Patch\n*** Update File: src/lib.rs\n@@\n-old\n+new\n*** End Patch\n"}),
),
);
assert_eq!(action["tool_name"], "edit");
assert_eq!(action["action_type"], "tool");
assert_eq!(action["payload_raw"], "/data/raw_agent_payload");
assert_eq!(action["action_id"], "call_7Q2");
assert!(action["payload_llm_cmd"].is_null());
}
#[test]
fn claude_code_bash_mcp_and_read() {
let bash = action_of("claude-code", claude("Bash", json!({"command": "ls -la"})));
assert_eq!(bash["harness_provider"], "anthropic");
assert_eq!(bash["action_id"], "toolu_01HbQ4tWm8XJk2vF9pL3sR7n");
assert_eq!(bash["payload_raw"], "/data/tool_input");
assert_eq!(
bash["payload_llm_cmd"][0]["tokens"][1],
json!({"t": "flag", "v": "-la"})
);
let mcp = action_of(
"claude-code",
claude(
"mcp__github__create_issue",
json!({"owner": "acme", "title": "x"}),
),
);
assert_eq!(mcp["action_type"], "mcp");
assert_eq!(mcp["tool_name"], "github.create_issue");
assert_eq!(
mcp["payload_llm_mcp"],
json!({"server": "github", "tool": "create_issue", "arguments": "/data/tool_input"})
);
assert!(mcp["payload_llm_cmd"].is_null());
let read = action_of(
"claude-code",
claude("Read", json!({"file_path": "/repo/a.rs"})),
);
assert_eq!(
(read["action_type"].as_str(), read["tool_name"].as_str()),
(Some("tool"), Some("read"))
);
assert!(read["payload_llm_mcp"].is_null() && read["payload_llm_cmd"].is_null());
let other = action_of(
"claude-code",
claude("KillShell", json!({"shell_id": "b1"})),
);
assert_eq!(other["tool_name"], "killshell");
}
#[test]
fn cursor_before_shell_has_no_call_id_and_uses_the_envelope_id() {
let native: Value = serde_json::from_str(include_str!(
"../../../tests/fixtures/cursor/before-shell-cli.json"
))
.unwrap();
let action = action_of("cursor", native);
assert_eq!(action["action_id"], EVENT_ID);
assert_eq!(action["harness_provider"], "cursor");
assert_eq!(action["tool_name"], "bash");
assert_eq!(action["cwd"], "/Users/dev/work");
assert_eq!(action["payload_raw"], "/data/raw_agent_payload");
assert_eq!(programs(&action["payload_llm_cmd"]), ["rm"]);
}
#[test]
fn cursor_pre_tool_use_shell_and_mcp() {
let native: Value = serde_json::from_str(include_str!(
"../../../tests/fixtures/cursor/pre-tool-shell-ide.json"
))
.unwrap();
let shell = action_of("cursor", native);
assert_eq!(shell["action_id"], "454c7fcf-fba9-48c8-9877-e1d8b11a351d");
assert_eq!(shell["tool_name"], "bash");
assert!(shell["cwd"].is_null(), "an empty cwd and no workspace root");
let before_mcp = json!({
"conversation_id": "c1", "generation_id": "g1", "model": "default",
"tool_name": "create_issue", "tool_input": "{\"title\":\"x\"}",
"mcp_server_name": "github", "url": "https://api.example.com/mcp",
"session_id": "c1", "hook_event_name": "beforeMCPExecution",
"cursor_version": "3.22.12", "workspace_roots": ["/Users/dev/work"]
});
let mcp = action_of("cursor", before_mcp);
assert_eq!(mcp["action_type"], "mcp");
assert_eq!(mcp["tool_name"], "github.create_issue");
let pre_mcp = json!({
"conversation_id": "c1", "tool_name": "MCP:create_issue",
"tool_input": {"title": "x"}, "tool_use_id": "tu-9", "session_id": "c1",
"hook_event_name": "preToolUse", "cursor_version": "3.22.12", "workspace_roots": []
});
let unnamed = action_of("cursor", pre_mcp);
assert_eq!(unnamed["tool_name"], "unknown.create_issue");
assert_eq!(unnamed["action_id"], "tu-9");
}
#[test]
fn cline_classic_sdk_list_and_mcp() {
let classic = action_of(
"cline",
cline_classic(
"execute_command",
json!({"command": "npm run build", "requires_approval": "false"}),
),
);
assert_eq!(classic["harness_provider"], "cline");
assert_eq!(classic["session_id"], "1791969100000");
assert_eq!(classic["cwd"], "/Users/dev/work/app");
assert_eq!(classic["tool_name"], "bash");
assert_eq!(classic["action_id"], EVENT_ID);
assert_eq!(programs(&classic["payload_llm_cmd"]), ["npm"]);
let sdk = action_of(
"cline",
json!({
"taskId": "conv_1",
"hookName": "tool_call",
"workspaceRoots": ["/Users/dev/work/app"],
"tool_call": {"id": "call_9", "name": "run_commands",
"input": {"commands": ["npm ci", "npm test -- --watch=false"]}},
"preToolUse": {"toolName": "run_commands",
"parameters": {"commands": "[\"npm ci\",\"npm test -- --watch=false\"]"}}
}),
);
assert_eq!(sdk["action_id"], "call_9");
let cmds = &sdk["payload_llm_cmd"];
assert_eq!(programs(cmds), ["npm", "npm"]);
assert_eq!(cmds[0]["is_chained"], true);
assert_eq!(cmds[1]["argv"], json!(["test", "--", "--watch=false"]));
let mcp = action_of(
"cline",
cline_classic(
"use_mcp_tool",
json!({"server_name": "github", "tool_name": "create_issue",
"arguments": "{\"title\":\"x\"}"}),
),
);
assert_eq!(mcp["action_type"], "mcp");
assert_eq!(mcp["tool_name"], "github.create_issue");
assert_eq!(mcp["payload_llm_mcp"]["arguments"], "/data/tool_input");
}
#[test]
fn shell_commands_are_split_and_typed() {
let multi = cmd("cd /repo\nnpm ci\nnpm test");
assert_eq!(programs(&multi), ["cd", "npm", "npm"]);
assert!(multi
.as_array()
.unwrap()
.iter()
.all(|c| c["is_chained"] == true));
let chain = cmd("cargo build && cargo test");
assert_eq!(programs(&chain), ["cargo", "cargo"]);
let redirect = cmd("echo hi > out.txt");
assert_eq!(
redirect[0]["tokens"],
json!([{"t": "program", "v": "echo"}, {"t": "arg", "v": "hi"},
{"t": "redirect", "v": ">", "target": "out.txt"}])
);
assert_eq!(redirect[0]["argv"], json!(["hi"]));
let sudo = cmd("sudo -u root rm -rf /tmp/x");
assert_eq!(programs(&sudo), ["rm"]);
assert_eq!(sudo[0]["is_chained"], false);
assert_eq!(
sudo[0]["tokens"],
json!([{"t": "wrapper", "v": "sudo"}, {"t": "wrapper", "v": "-u"},
{"t": "wrapper", "v": "root"}, {"t": "program", "v": "rm"},
{"t": "flag", "v": "-rf"}, {"t": "arg", "v": "/tmp/x"}])
);
assert_eq!(programs(&cmd("sudo -v && ls")), ["sudo", "ls"]);
let assigned = cmd("FOO=1 make build");
assert_eq!(programs(&assigned), ["make"]);
assert_eq!(
assigned[0]["tokens"][0],
json!({"t": "assignment", "v": "FOO=1"})
);
let broken = action_of(
"claude-code",
claude("Bash", json!({"command": "echo 'unbalanced"})),
);
assert!(broken["payload_llm_cmd"].is_null());
assert_eq!(broken["tool_name"], "bash");
}
#[test]
fn only_tool_events_get_an_action() {
let prompt = hook_envelope(
"claude-code",
"user_prompt_submit",
json!({"session_id": "s", "hook_event_name": "UserPromptSubmit", "prompt": "hi"}),
);
assert_eq!(to_action(&prompt), None);
}
#[test]
fn an_oversized_action_drops_tokens_then_commands() {
let many = vec!["echo aaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 200].join(" && ");
let action = cmd(&many);
assert!(action
.as_array()
.unwrap()
.iter()
.all(|c| c.get("tokens").is_none()));
let huge = vec!["x"; 4_000].join(";");
assert!(cmd(&huge).is_null());
}
#[test]
fn an_llm_action_is_valid() {
let action = llm_action(
"unknown",
None,
TIME,
"0190aaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
ActionLlmParse {
provider: Some("anthropic".into()),
model: Some("claude-opus-4-8".into()),
input_tokens: Some(1),
output_tokens: Some(2),
cache_read_tokens: Some(3),
cache_write_tokens: Some(4),
},
);
assert_valid(&action);
assert_eq!(action["harness_provider"], Value::Null);
assert_eq!(action["timestamp"], TIME_MS);
}
#[test]
#[ignore = "writes a file outside the repository"]
fn action_examples_dump() {
use crate::model_relay::capture::{CostBasis, Usage};
use crate::model_relay::emit::{assemble_data, assemble_event, relay_action, Observation};
use crate::model_relay::session::{Assurance, Resolved};
use crate::model_relay::wire_format::WireFormat;
let mut examples = Vec::new();
let mut hook = |agent: &str, title: &str, source: &str, native: Value| {
let envelope = hook_envelope(source, "pre_tool_use", native);
let action = to_action(&envelope).expect("an action");
assert_valid(&action);
examples.push(json!({
"agent": agent, "action_type": action["action_type"], "title": title,
"input_envelope": envelope, "action": action,
}));
};
hook(
"claude-code",
"Bash: chained npm test && git push",
"claude-code",
claude(
"Bash",
json!({"command": "npm test && git push origin develop", "description": "Run tests then push"}),
),
);
hook(
"claude-code",
"MCP: mcp__github__create_issue",
"claude-code",
claude(
"mcp__github__create_issue",
json!({"owner": "acme", "repo": "app", "title": "Flaky test"}),
),
);
hook(
"claude-code",
"Read",
"claude-code",
claude("Read", json!({"file_path": "/repo/src/main.rs"})),
);
hook(
"claude-code",
"Bash: multi-line script",
"claude-code",
claude("Bash", json!({"command": "cd /repo\nnpm ci\nnpm test"})),
);
hook(
"claude-code",
"Bash: redirect to file",
"claude-code",
claude(
"Bash",
json!({"command": "git log --oneline -20 > /tmp/log.txt 2>> /tmp/err.log"}),
),
);
hook(
"claude-code",
"Bash: sudo wrapper",
"claude-code",
claude(
"Bash",
json!({"command": "sudo -u root rm -rf /var/cache/app"}),
),
);
hook(
"claude-code",
"Bash: FOO=1 assignment prefix",
"claude-code",
claude(
"Bash",
json!({"command": "RUST_LOG=debug FOO=1 cargo test --workspace"}),
),
);
hook(
"claude-code",
"Bash: tokenizer failure (unbalanced quote)",
"claude-code",
claude("Bash", json!({"command": "echo 'unbalanced"})),
);
hook(
"codex-cli",
"Bash",
"codex-cli",
codex("Bash", json!({"command": "cargo test --workspace"})),
);
hook(
"codex-cli",
"apply_patch",
"codex-cli",
codex(
"apply_patch",
json!({"input": "*** Begin Patch\n*** Update File: src/lib.rs\n@@\n-old\n+new\n*** End Patch\n"}),
),
);
hook(
"cursor",
"beforeShellExecution (no call id)",
"cursor",
serde_json::from_str(include_str!(
"../../../tests/fixtures/cursor/before-shell-cli.json"
))
.unwrap(),
);
hook(
"cursor",
"preToolUse Shell",
"cursor",
serde_json::from_str(include_str!(
"../../../tests/fixtures/cursor/pre-tool-shell-ide.json"
))
.unwrap(),
);
hook(
"cursor",
"beforeMCPExecution",
"cursor",
json!({
"conversation_id": "5fb6e06f-ba89-4692-b119-a2a49e0e3042", "generation_id": "5fb6e06f-ba89-4692-b119-a2a49e0e3042",
"model": "default", "tool_name": "create_issue", "tool_input": "{\"title\":\"Flaky test\"}",
"mcp_server_name": "github", "url": "https://api.githubcopilot.com/mcp/",
"session_id": "5fb6e06f-ba89-4692-b119-a2a49e0e3042", "hook_event_name": "beforeMCPExecution",
"cursor_version": "3.22.12", "workspace_roots": ["/Users/dev/work"]
}),
);
hook(
"cursor",
"preToolUse MCP:<tool> (server not named on this event)",
"cursor",
json!({
"conversation_id": "7dc1864a-551b-4cf8-be04-21124ba704ff", "generation_id": "ad343d7e-47aa-4949-a7c7-2098ca482044",
"model": "grok-4.6", "tool_name": "MCP:create_issue", "tool_input": {"title": "Flaky test"},
"tool_use_id": "9b1f0c2e-1d4a-4b7e-8c3f-5a6d7e8f9012", "cwd": "", "session_id": "7dc1864a-551b-4cf8-be04-21124ba704ff",
"hook_event_name": "preToolUse", "cursor_version": "3.22.12", "workspace_roots": ["/Users/dev/work"]
}),
);
hook(
"cline",
"execute_command (classic host)",
"cline",
cline_classic(
"execute_command",
json!({"command": "npm run build", "requires_approval": "false"}),
),
);
hook(
"cline",
"run_commands list (SDK host)",
"cline",
json!({
"clineVersion": "4.1.17", "hookName": "tool_call", "taskId": "conv_1",
"workspaceRoots": ["/Users/dev/work/app"],
"tool_call": {"id": "call_9", "name": "run_commands", "input": {"commands": ["npm ci", "npm test -- --watch=false"]}},
"preToolUse": {"toolName": "run_commands", "parameters": {"commands": "[\"npm ci\",\"npm test -- --watch=false\"]"}}
}),
);
hook(
"cline",
"use_mcp_tool",
"cline",
cline_classic(
"use_mcp_tool",
json!({
"server_name": "github", "tool_name": "create_issue", "arguments": "{\"title\":\"Flaky test\"}"
}),
),
);
hook(
"codex-cli",
"MCP: mcp__github__create_issue",
"codex-cli",
codex(
"mcp__github__create_issue",
json!({"title": "Flaky test", "repo": "acme/app"}),
),
);
hook(
"cursor",
"preToolUse Read",
"cursor",
json!({
"conversation_id": "7dc1864a-551b-4cf8-be04-21124ba704ff", "generation_id": "ad343d7e-47aa-4949-a7c7-2098ca482044",
"model": "claude-opus-4-8", "tool_name": "Read", "tool_input": {"file_path": "/Users/dev/work/src/app.ts"},
"tool_use_id": "4c2d8e1f-6a7b-4c3d-9e8f-0a1b2c3d4e5f", "cwd": "/Users/dev/work", "session_id": "7dc1864a-551b-4cf8-be04-21124ba704ff",
"hook_event_name": "preToolUse", "cursor_version": "3.22.12", "workspace_roots": ["/Users/dev/work"]
}),
);
hook(
"cline",
"read_file (classic host)",
"cline",
cline_classic("read_file", json!({"path": "src/app.ts"})),
);
let relay = |agent: &str,
title: &str,
wire: WireFormat,
model: &str,
session: &str,
usage: Usage| {
let mut obs = Observation::none();
obs.measured = true;
obs.event_id = "0192f3a1-7c2e-7b4d-8e9f-1a2b3c4d5e6f".to_string();
obs.occurred_at = TIME.to_string();
obs.model = Some(model.to_string());
obs.model_known = true;
obs.install_id = "agt_550e8400e29b41d4a716446655440000".to_string();
obs.wire_format = wire;
obs.session = Resolved {
agent_id: Some(obs.install_id.clone()),
source: Some(agent.to_string()),
session_id: Some(session.to_string()),
assurance: Assurance::Attested,
hook_seen: Some(true),
agent_thread_id: None,
};
let data = assemble_data(&obs, &usage, CostBasis::ProviderReported, None, true);
let event = assemble_event(&obs, data, &crate::privacy::PrivacyFilter::new(&[]));
let (provider, model) = obs.identity(model);
let action = relay_action(&obs, &usage, &provider, &model);
assert_valid(&action);
json!({
"agent": agent, "action_type": "llm", "title": title,
"input_envelope": event.envelope, "action": action,
})
};
examples.push(relay(
"claude-code",
"Model relay: Anthropic Messages",
WireFormat::AnthropicMessages,
"claude-opus-4-8",
"8f2c1e4a-6b1d-4c7e-9f3a-2d5b7c9e1f04",
Usage {
input_tokens: 412,
cache_read: 18_240,
cache_write: 1_024,
eph_5m: 1_024,
eph_1h: 0,
output_tokens: 389,
},
));
examples.push(relay(
"codex-cli",
"Model relay: OpenAI Responses",
WireFormat::OpenAiResponses,
"gpt-5.2-codex",
"s-41",
Usage {
input_tokens: 2_310,
cache_read: 9_984,
cache_write: 0,
eph_5m: 0,
eph_1h: 0,
output_tokens: 655,
},
));
examples.push(relay(
"cursor",
"Model relay: Cursor backend (Connect-RPC)",
WireFormat::CursorConnectRpc,
"claude-opus-4-8",
"7dc1864a-551b-4cf8-be04-21124ba704ff",
Usage {
input_tokens: 5_120,
cache_read: 0,
cache_write: 0,
eph_5m: 0,
eph_1h: 0,
output_tokens: 742,
},
));
examples.push(relay(
"cline",
"Model relay: OpenAI-compatible Chat Completions",
WireFormat::OpenAiChatCompletions,
"gpt-5.2",
"conv_1",
Usage {
input_tokens: 3_400,
cache_read: 1_280,
cache_write: 0,
eph_5m: 0,
eph_1h: 0,
output_tokens: 512,
},
));
let path = std::env::var("ACTION_EXAMPLES_OUT").unwrap_or_else(|_| {
concat!(env!("CARGO_MANIFEST_DIR"), "/target/action-examples.json").to_string()
});
let body = serde_json::to_string_pretty(&examples).unwrap();
std::fs::write(&path, body + "\n").expect("write the examples");
println!("wrote {} examples to {path}", examples.len());
}
}