English | 简体中文
Use this guide when you want LoongSuite Pilot to collect telemetry from a new AI coding agent. The goal is to make the new integration look like every other supported agent to users: auto-detectable, configurable, and exported through the same event schema and output backends.
Choose the lightest integration that the target agent supports.
| Integration | Use When |
|---|---|
| Hook | The agent can run a command on lifecycle, prompt, response, or tool events. |
| Plugin injection | The agent can load a local plugin from its config file. |
| Local log or session polling | The agent already writes structured local files. |
| SQLite polling | The agent stores activity in a local SQLite database. |
| CLI or API polling | The agent exposes a local command or API for activity data. |
Prefer hooks or plugins when they can emit structured event records. They are easier to normalize and usually provide better coverage for tool calls and token usage.
Every new agent integration should provide:
- An agent definition in
agents.d/<agent-id>.json. - A hook, plugin, or polling source that produces activity records.
- An input implementation that converts source records into
AgentActivityEntry. - A
ClientTypevalue for the new agent. - Registration in the collector startup path when the input is not generic.
- Tests or fixtures that prove the normalized output matches Output Event Schema.
Agent definitions describe how Pilot detects and deploys an integration. Built-in definitions are loaded from agents.d/*.json; local runtime definitions can override them from ~/.loongsuite-pilot/agents.d.local/.
Hook-based example:
{
"id": "my-agent",
"displayName": "My Agent",
"deployMode": "hook",
"detection": {
"paths": ["~/.my-agent"],
"commands": ["my-agent"]
},
"hook": {
"settingsPath": "~/.my-agent/settings.json",
"events": ["Stop", "PreToolUse", "PostToolUse"],
"hookCommand": "$PILOT_DATA/hooks/my-agent-loongsuite-pilot-hook.sh",
"format": "nested",
"matcher": "*"
},
"input": {
"type": "hook-jsonl",
"logDir": "$PILOT_DATA/logs/my-agent"
}
}Plugin-injection example:
{
"id": "my-agent",
"displayName": "My Agent",
"deployMode": "plugin-inject",
"detection": {
"paths": ["~/.config/my-agent"],
"commands": ["my-agent"]
},
"pluginInject": {
"configPaths": [
"~/.config/my-agent/config.json"
],
"pluginSpec": "file://$PILOT_DATA/plugins/my-agent/plugin.mjs",
"pluginId": "loongsuite-pilot-my-agent"
},
"input": {
"type": "hook-jsonl",
"logDir": "$PILOT_DATA/logs/my-agent"
}
}Important fields:
| Field | Purpose |
|---|---|
id |
Stable agent ID used in config, output, and admission control. |
displayName |
Human-readable agent name. |
deployMode |
hook, plugin-inject, or plugin-probe. |
detection.paths |
Local paths that indicate the agent is installed. |
detection.commands |
Commands that indicate the agent is installed. |
hook |
Hook settings path, events, command, and format. Required for hook mode. |
pluginInject |
Config paths and plugin spec. Required for plugin injection mode. |
input |
Source type and source location for the collector input. |
When adding a
plugin-injectagent, also register it in the uninstaller (deploy/installer-opensource.sh/.ps1) so its injected spec is removed on uninstall. Plugin-inject agents are additionally self-healed at runtime by the hook watchdog, which re-injects the spec if another tool overwrites the config.
For hook and plugin integrations, make the hook or plugin write newline-delimited JSON records to:
~/.loongsuite-pilot/logs/<agent-id>/<agent-id>-YYYY-MM-DD.jsonl
Use canonical dotted fields whenever possible:
{
"time_unix_nano": "1778586618041000000",
"observed_time_unix_nano": "1778586618041000000",
"event.id": "event-uuid",
"event.name": "tool.result",
"user.id": "user-id",
"gen_ai.session.id": "session-id",
"gen_ai.agent.type": "my-agent",
"gen_ai.provider.name": "openai",
"gen_ai.tool.name": "bash",
"gen_ai.tool.call.id": "call-id",
"gen_ai.tool.call.duration": 423
}Keep source-specific fields under agent.<agent-id>.* so public output fields stay stable.
These fields may be used by normalization and enrichment, but SLS and local JSONL outputs drop them by default.
Use an existing input style that matches the source:
| Source | Recommended Input Style |
|---|---|
| Hook or plugin JSONL | Extend BaseHookInput, or reuse transformHookRecord when the source already emits canonical dotted fields. |
| Local session files | Extend BaseSessionInput. |
| SQLite database | Extend BaseSqliteInput. |
| IDE history snapshots | Extend BaseIdeInput. |
| CLI telemetry files | Extend BaseCliForwarder. |
| Local CLI/API | Extend BaseInput directly. |
The input should:
- Incrementally read only new records.
- Preserve checkpoints across restarts.
- Emit
AgentActivityEntryobjects. - Avoid exporting raw sensitive content unless policy allows it.
- Attach stable session, turn, tool call, and error identifiers when available.
When a custom input class is needed:
- Add the agent to
src/types/client-type.ts. - Import and register the input in
src/core/orchestrator.ts. - Map listener IDs to the public agent ID so
agent-control.jsonandconfig.agentswork. - Add default listener configuration when the input needs polling.
- Add the built-in agent definition to
agents.d/.
If your integration follows an existing hook or plugin record shape, keep the code change smaller by reusing the existing base input and transformHookRecord. The input still needs to be registered in the collector startup path.
Before marking an integration ready:
- Support
captureMessageContent: falsefor prompts, completions, tool arguments, and tool results when the agent exposes those fields. - Keep secrets out of source-specific extension fields unless they are required and subject to masking.
- Verify
mask.mode: allmasks API keys, access keys, private keys, and database URLs in emitted output. See Data Masking. - Fail open in hook/plugin code so the agent is never blocked by telemetry collection.
At minimum, add tests or fixtures for:
- Agent detection and deployment definition parsing.
- Hook or plugin record generation.
- Input checkpointing and incremental reads.
- Normalized
event.namevalues. - LLM request/response fields.
- Tool call/result correlation.
- Token fields when the source exposes usage.
- Content capture disabled mode.
- Masking enabled mode.
When adding a public agent, update:
- Supported agent tables in README and Product Overview.
- Configuration examples if the agent needs special setup.
- Data Masking if the agent emits new sensitive content fields.
- Output Event Schema only when adding stable public fields.