Monitoring CLIDE
CLIDE gives command-line scripts a form, runs them, writes new ones with an AI agent, installs ready-made ones from its Tool Marketplace, and updates itself. This folder is for whoever looks after the computers it runs on: what CLIDE can record, where it goes, and how to set it for every computer at once.
- What CLIDE records: one list of events, below. Each event is a flat set
of fields named as OpenTelemetry
names them where it has a name, and under
clide.where it doesn't. - Where it goes: a log file on the computer (one JSON object per line), an OpenTelemetry endpoint (OTLP over HTTP, JSON), or both.
- Who turns it on: the person, in Settings → Monitoring, or your organization, through a configuration profile (macOS), Group Policy or Intune (Windows), or a file (Linux). Both outputs are off until one of them turns it on. What the organization sets shows in Settings as "Set by your organization" and can't be changed there.
- Nothing goes to CLIDE's makers. The endpoint is yours, or the person's.
The format is beta, like CLIDE. Fields may still change until CLIDE 1.0.
When a field is renamed or removed, or its meaning changes, schema_version
goes up. Adding a field or an event doesn't change it. Ignore fields you don't
know.
What it is, and what it isn't
Monitoring shows what CLIDE did. It doesn't stop anyone doing anything. A person can delete the local log, quit CLIDE, or run a tool's script in a terminal, where CLIDE never sees it.
- For an audit trail, use the endpoint, or a collector that ships the log as it's written. Once a line has left the computer, deleting the file doesn't remove it.
- It adds to your endpoint security software; it doesn't replace it. That software already sees every process on the computer. CLIDE adds what only CLIDE knows: which tool ran and which version of its files, where that tool came from (the Marketplace, an AI agent, a person), which agent and model wrote it, and how the run was started.
What CLIDE can't see:
- A pipeline exported as a script and run in a terminal.
- A tool's script run by hand, outside CLIDE.
- A checkpoint's test of its assertions runs no program, so it isn't a run.
An old checkpoint that runs a script of its own (
clide: 1) isn't recorded yet either.
clide run in a terminal is recorded, as clide.source: "cli", with the same
settings and policy as CLIDE.
The log file
| OS | Where |
|---|---|
| macOS | ~/Library/Logs/CLIDE/monitor.jsonl (Console.app shows it under Log Reports) |
| Windows | %LOCALAPPDATA%\CLIDE\Logs\monitor.jsonl |
| Linux | $XDG_STATE_HOME/clide/logs/monitor.jsonl, by default ~/.local/state/clide/logs/monitor.jsonl |
The folder can be changed in Settings or by policy (logFolder).
- One event per line, each a whole JSON object, ending in a newline.
- Rotation: past 10 MB the file becomes
monitor.1.jsonland a new one starts; the five older files are kept (monitor.1.jsonlis the newest), and the oldest past five is deleted. A line is never split across files. - More than one writer: CLIDE and
clide runboth append to it. Lines never interleave. A line written just as the file is rotated can land at the end ofmonitor.1.jsonl. - A crash mid-line: the next time CLIDE writes, it ends that line first, so every line after it is whole JSON. Skip a line that doesn't parse.
- When writing fails (a full disk, no permission), runs carry on. CLIDE
says so once on its Start screen and in Settings → Monitoring, and counts the
lines it lost: a
monitoring.droppedevent says how many once writing works again.
The OpenTelemetry endpoint
CLIDE sends to <endpoint>/v1/logs and <endpoint>/v1/traces (OTLP over
HTTP, JSON). An address that already ends in one of those paths is used as it
is for that signal.
- Every event is a log record. The resource is CLIDE:
service.name: clide,service.version,host.name,os.type,os.version. The record'seventNameandbodyare the event's name; its attributes are the event's other fields. Severity isWARNforrun.failed,agent.failed,dependency.missing,monitoring.dropped,monitoring.policy_problemand a run that failed or timed out, andINFOfor the rest. - Each run is also a trace: a pipeline's run with a span per step and per try, once it ends, and a tool's run from CLIDE's window as one span.
- Headers, for a service that wants a key: set in Settings (the value is
kept in the Keychain, Windows Credential Manager or the Linux keyring, never
in a settings file or an export) or by policy (
endpointHeaders). On a Linux desktop that logs in by itself (a Raspberry Pi), the keyring is locked, and saving a header asks for its password first. Where there's no keyring at all, the value goes in a file in CLIDE's data folder only the person can read. - Events go a few seconds apart, in batches. When the endpoint can't be reached, CLIDE tries again twice, then drops the batch and counts it, as for the log. A run is never held up.
clide run --otlp <address>sends that run's trace to another address besides the one set, never instead of it.
Fields on every event
| Field | |
|---|---|
schema_version | 1 |
time | When it happened: ISO 8601, UTC, milliseconds (2026-10-22T14:03:07.412Z) |
event.name | The event, below |
user.name | The account CLIDE runs as |
host.name | The computer's name |
os.type | darwin, windows or linux |
os.version | macOS's version (15.6); the kernel's on Linux; Windows' build (10.0.22631) |
service.version | CLIDE's version |
clide.source | app (CLIDE's window) or cli (clide run in a terminal) |
Values: what's hidden unless recorded
Record values is off unless the person or the policy (recordValues)
turns it on. While it's off:
- Arguments: each value from a tool's form is
[REDACTED]. Flag names, the script and fixed arguments stay, and so does the count:["{{toolDir}}/report.sh", "--title", "[REDACTED]", "--out", "[REDACTED]/report.md"]becomes, with the folders filled in,["/Users/pat/Tools/report/report.sh", "--title", "[REDACTED]", "--out", "[REDACTED]/report.md"]. - Files a run reads and writes: counted, and their kinds (
image,document,audio…), not their paths. - Web addresses: their host only (
url.domain). - Reference files given to an agent: counted, not named.
With it on, those fields also carry the values themselves:
process.command_args as the run had them, process.working_directory,
clide.files.read.paths, clide.files.written.paths, url.full,
clide.references.names and clide.batch.record.
Never recorded, either way: environment variables, anything a run prints, the contents of what tools make, what a person asks an AI agent and what it answers, the contents of reference files, and a header's value.
Tool and pipeline paths are always recorded: they say which tool ran.
Events
What ran
run.started: a tool's run, or a pipeline's tool step, as its program starts.
| Field | |
|---|---|
clide.run.id | The run's id, as CLIDE's History has it; the same on its end |
clide.tool.name, clide.tool.path | The tool |
clide.tool.hash | SHA-256 over all the tool's files: see A tool's hash |
clide.tool.files | Each file: { "path": "report.sh", "sha256": "…" }, its path relative to the tool's folder |
clide.pipeline.path, clide.pipeline.hash, clide.pipeline.run.id, clide.step, clide.step.attempt | A pipeline's step only |
clide.trigger | manual (Run in the window), preset, batch, pipeline (a step of a pipeline run in CLIDE), cli (a step of clide run) |
clide.preset, clide.batch | The preset or batch preset it came from, by name |
process.executable.name | The program: bash, python3, bun; process.executable.path too when the tool gives a path |
process.command_args | Its arguments, values hidden unless recorded |
clide.args.count | How many arguments |
run.completed: the run ended, however it ended. The tool's fields as on
its start, and:
| Field | |
|---|---|
clide.status | done, failed, cancelled or timed-out |
process.exit.code | Its exit code; null when it was stopped |
clide.duration_ms | How long it ran |
clide.message | What CLIDE said about it, when it said something |
clide.files.read, clide.files.written | How many of the person's files it read and wrote |
clide.files.kinds | Those files by kind: { "document": 2, "image": 1 } |
run.failed: the program couldn't be started at all (no such program, no
permission), after run.started. The tool's fields, the program,
error.type: "start_failed" and error.message.
run.new_code: the first run, on this computer, of a tool whose files are
as they are now: a new tool, or one whose files changed. After its
run.started. The tool's fields. This is the event to alert on.
Where code came from
tool.added: a tool CLIDE hadn't seen: made by an agent, installed from
the Marketplace, or found new in a tool folder it looks at. clide.tool.path,
clide.tool.hash, clide.tool.files, and who (below).
tool.changed: a tool's files changed. clide.tool.path,
clide.tool.hash.before, clide.tool.hash, clide.tool.files.changed (which
files, by relative path), clide.tool.files, and who.
tool.removed: a tool gone from a tool folder CLIDE looks at.
clide.tool.path, clide.tool.hash.before, and who.
Who, on all three:
clide.by | And |
|---|---|
agent | clide.agent.name, clide.agent.model: an AI agent wrote or edited it |
marketplace | clide.marketplace.id, clide.marketplace.version: installed or updated from the Tool Marketplace |
clide | clide.change: changed in CLIDE by the person (the Code tab, a restored version, a rename, presets, tags) |
outside | clide.detected: true: changed outside CLIDE, and noticed later: right before the tool's next run (and before its run.started), when the tool is opened, or when its tool folder is looked at again (as CLIDE starts, and when it comes back to the front, at most once a minute) |
The first time CLIDE sees a tool it only remembers it. A tool folder's first
look says nothing; tools new to it after that are tool.added.
tool.opened_from_os: a .clide file double-clicked, opened with CLIDE,
or dropped on its icon. clide.tool.path.
AI agents
agent.started: one turn of the person's AI agent.
| Field | |
|---|---|
clide.agent.name | The agent: claude, codex, gemini, or a custom agent's id |
clide.agent.model | The model, by its full name when the agent said; null for its default |
clide.agent.purpose | create (a new tool or pipeline), edit (changing one, fixing a failed run included), batch_draft (drafting a batch preset) |
clide.tool.path | The tool it works on; for create, the folder the new tool goes in |
clide.references.count | How many files the person gave it to read |
agent.completed: the turn ended. The same fields, and clide.status
(done, failed, cancelled), process.exit.code, clide.duration_ms.
agent.failed: the agent's program couldn't be started.
error.type: "start_failed", error.message.
What runs touched
The files a run read and wrote are on its run.completed, above.
fetch: a web address CLIDE fetched itself. url.domain, url.full
([REDACTED] unless values are recorded), clide.fetch.for (batch_source:
a batch preset's records; marketplace: the Marketplace's index and tools),
clide.fetch.ok. Screenshots in the Marketplace aren't recorded. What a
tool's own script fetches is that script's business, and isn't seen.
CLIDE itself
| Event | Fields |
|---|---|
app.started | host.arch; clide.monitoring.log, clide.monitoring.endpoint, clide.monitoring.record_values (what's on); clide.monitoring.policy (the keys your policy sets) |
app.quit | Written to the log as CLIDE quits. It reaches the endpoint only if it's sent in time: CLIDE waits a second and a half for it at most. |
app.updated | clide.version.from, clide.version.to: on the first start after an update |
settings.changed | clide.settings.section and clide.settings.key; clide.settings.from and clide.settings.to for settings that hold nothing personal. Sections and keys: runs (runsAtOnce, keepDays with values; pipelineRuns, keepDaysFor), appearance (theme), agents (agent with its new value; customAgents), toolFolders (folders), monitoring (recordValues with values; logFolder, endpoint, endpointHeaders) |
dependency.missing | clide.tool.path, clide.dependency.program: a program a tool needs isn't on this computer (once per tool and program while CLIDE runs) |
monitoring.changed | clide.output (log or endpoint), clide.enabled, clide.by (person or organization). When an output is turned off, this is its last event. |
monitoring.test | From Settings → Monitoring's Send a test event |
monitoring.dropped | clide.output, clide.dropped.count: events lost while writing or sending failed |
monitoring.policy_problem | clide.policy.problem: a key of your policy CLIDE couldn't use, and left out |
A tool's hash
A CLIDE tool is a .clide file and the files it runs: report.clide runs
./report.sh. A tool's hash covers all of them:
- The files are the
.clideand every file itsrun.commandandrun.argsname inside its folder (./report.sh,{{toolDir}}/lib.py). - Each file's SHA-256 is taken, and a line written for it: its path relative to the tool's folder, a tab, its SHA-256, a newline.
- The lines are sorted by path and joined, and
clide.tool.hashis the SHA-256 of that text.
So the hash changes when any of the tool's files changes, is added, is
removed or is renamed, and clide.tool.files says which. A pipeline's step
runs this run's copy of the tool's .clide with its scripts where the tool
is, and its hash is taken that way.
Outside the hash: files a script loads by itself (a library it imports, a
file it sources) unless the tool names them, and the programs it calls from
the PATH, which process.executable.name names.
Setting it for every computer
Each key your policy sets wins over the person's choice and is locked in
Settings; a key it leaves out stays the person's. A policy CLIDE can't read,
or a key with a bad value, is left out key by key, said in Settings, and
recorded as monitoring.policy_problem. CLIDE reads the policy as it starts
and whenever Settings opens.
| Key | Type | |
|---|---|---|
logEnabled | true / false | Write the log |
logFolder | text | The log's folder: a full path |
endpoint | text | The OpenTelemetry endpoint: an http or https address, with no key in it |
endpointHeaders | names and values | Headers sent to the endpoint |
recordValues | true / false | Record values |
macOS: a configuration profile
clide-monitoring.mobileconfig sets them for
the preference domain tools.clide. Change its values, remove the keys you
leave to people, and deploy it from your MDM (Jamf, Kandji, Intune…) as a
device profile. CLIDE reads /Library/Managed Preferences/tools.clide.plist,
then the signed-in person's
/Library/Managed Preferences/<user>/tools.clide.plist for keys the first
doesn't set.
Windows: Group Policy or Intune
windows/clide.admx and
windows/en-US/clide.adml: copy them to
PolicyDefinitions (and PolicyDefinitions\en-US), or import them into
Intune. The policies are under CLIDE → Monitoring, for the computer or the
user. They write HKLM\SOFTWARE\Policies\CLIDE or
HKCU\SOFTWARE\Policies\CLIDE: logEnabled and recordValues as DWORD 1 or
0, logFolder and endpoint as strings, and the headers as string values
under the endpointHeaders key. The computer's keys win over the user's.
Linux: a file
policy.json, at /etc/clide/policy.json, put there with
whatever configures your machines (Ansible, Puppet, Chef):
{
"logEnabled": true,
"recordValues": false,
"endpoint": "https://otel-collector.example.com:4318",
"endpointHeaders": { "x-api-key": "replace-with-your-key" }
}
Collecting the log
The paths below are macOS's; Windows' is
C:\Users\*\AppData\Local\CLIDE\Logs\monitor.jsonl, Linux's
/home/*/.local/state/clide/logs/monitor.jsonl. Read the current file only:
rotated ones were read before they were renamed.
Fluent Bit (with the json parser from its parsers.conf):
[INPUT]
Name tail
Path /Users/*/Library/Logs/CLIDE/monitor.jsonl
Parser json
Tag clide
Vector:
sources:
clide:
type: file
include: ["/Users/*/Library/Logs/CLIDE/monitor.jsonl"]
transforms:
clide_events:
type: remap
inputs: [clide]
source: ". = parse_json!(.message)"
Splunk Universal Forwarder (inputs.conf):
[monitor:///Users/*/Library/Logs/CLIDE/monitor.jsonl]
sourcetype = _json
Elastic Agent or Filebeat:
filebeat.inputs:
- type: filestream
id: clide
paths: ["/Users/*/Library/Logs/CLIDE/monitor.jsonl"]
parsers:
- ndjson:
target: ""
Or skip the file: set the endpoint to your OpenTelemetry Collector.
An example line
{"schema_version":1,"time":"2026-10-22T14:03:07.412Z","event.name":"run.completed","user.name":"pat","host.name":"pat-laptop","os.type":"darwin","os.version":"15.6","service.version":"0.5.0","clide.source":"app","clide.run.id":"run-1761141787000-1","clide.tool.name":"Make a report","clide.tool.path":"/Users/pat/Tools/report/report.clide","clide.tool.hash":"9f2c…","clide.tool.files":[{"path":"report.clide","sha256":"41ab…"},{"path":"report.sh","sha256":"c07e…"}],"clide.status":"done","process.exit.code":0,"clide.duration_ms":1840,"clide.files.read":1,"clide.files.written":1,"clide.files.kinds":{"document":2}}