traceforge-toolkit 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. traceforge/__init__.py +72 -0
  2. traceforge/__main__.py +5 -0
  3. traceforge/_generated.py +254 -0
  4. traceforge/adapters/__init__.py +12 -0
  5. traceforge/adapters/base.py +82 -0
  6. traceforge/adapters/genai_otel.py +164 -0
  7. traceforge/adapters/mapped_json.py +297 -0
  8. traceforge/adapters/otel.py +220 -0
  9. traceforge/boundary/__init__.py +46 -0
  10. traceforge/boundary/data/boundary-model.joblib +0 -0
  11. traceforge/boundary/decode.py +87 -0
  12. traceforge/boundary/features.py +137 -0
  13. traceforge/boundary/inference.py +267 -0
  14. traceforge/boundary/inferencer.py +146 -0
  15. traceforge/classify/__init__.py +95 -0
  16. traceforge/classify/cmd.py +109 -0
  17. traceforge/classify/coding.py +213 -0
  18. traceforge/classify/config.py +554 -0
  19. traceforge/classify/core.py +266 -0
  20. traceforge/classify/data/binary_info.yaml +358 -0
  21. traceforge/classify/data/canonical_tools.yaml +251 -0
  22. traceforge/classify/data/effect_overrides.yaml +480 -0
  23. traceforge/classify/data/mcp_profiles.yaml +711 -0
  24. traceforge/classify/data/recommendation_rules.yaml +111 -0
  25. traceforge/classify/data/risk.yaml +534 -0
  26. traceforge/classify/data/shell_defaults.yaml +95 -0
  27. traceforge/classify/data/shell_rules.yaml +1192 -0
  28. traceforge/classify/data/tool_classifications.yaml +215 -0
  29. traceforge/classify/data/verb_inference.yaml +218 -0
  30. traceforge/classify/mcp.py +181 -0
  31. traceforge/classify/phases.py +75 -0
  32. traceforge/classify/powershell.py +93 -0
  33. traceforge/classify/registry.py +138 -0
  34. traceforge/classify/risk.py +553 -0
  35. traceforge/classify/rules.py +215 -0
  36. traceforge/classify/schema.yaml +282 -0
  37. traceforge/classify/shell.py +503 -0
  38. traceforge/classify/tools.py +91 -0
  39. traceforge/classify/workflow.py +32 -0
  40. traceforge/cli/__init__.py +42 -0
  41. traceforge/cli/config_cmd.py +130 -0
  42. traceforge/cli/detect.py +46 -0
  43. traceforge/cli/download_cmd.py +74 -0
  44. traceforge/cli/factory.py +60 -0
  45. traceforge/cli/gate_cmd.py +30 -0
  46. traceforge/cli/init_cmd.py +86 -0
  47. traceforge/cli/replay.py +130 -0
  48. traceforge/cli/runner.py +181 -0
  49. traceforge/cli/score.py +217 -0
  50. traceforge/cli/status.py +65 -0
  51. traceforge/cli/watch.py +297 -0
  52. traceforge/config/__init__.py +80 -0
  53. traceforge/config/defaults.py +149 -0
  54. traceforge/config/loader.py +239 -0
  55. traceforge/config/mappings.py +104 -0
  56. traceforge/config/models.py +579 -0
  57. traceforge/enricher.py +576 -0
  58. traceforge/formatting/__init__.py +12 -0
  59. traceforge/formatting/budget.py +92 -0
  60. traceforge/formatting/density.py +154 -0
  61. traceforge/gate/__init__.py +17 -0
  62. traceforge/gate/client.py +145 -0
  63. traceforge/gate/external.py +305 -0
  64. traceforge/gate/registry.py +108 -0
  65. traceforge/gate/server.py +174 -0
  66. traceforge/gates/__init__.py +8 -0
  67. traceforge/gates/pii.py +352 -0
  68. traceforge/gates/pii_patterns.yaml +228 -0
  69. traceforge/governance/__init__.py +121 -0
  70. traceforge/governance/assessor.py +441 -0
  71. traceforge/governance/budget.py +59 -0
  72. traceforge/governance/canonical.py +56 -0
  73. traceforge/governance/codec.py +414 -0
  74. traceforge/governance/context.py +249 -0
  75. traceforge/governance/drift.py +196 -0
  76. traceforge/governance/emitter.py +234 -0
  77. traceforge/governance/envelope.py +138 -0
  78. traceforge/governance/ifc.py +364 -0
  79. traceforge/governance/integrity.py +162 -0
  80. traceforge/governance/labeler.py +250 -0
  81. traceforge/governance/mcp_drift.py +328 -0
  82. traceforge/governance/monitor.py +539 -0
  83. traceforge/governance/observer.py +276 -0
  84. traceforge/governance/persistence.py +401 -0
  85. traceforge/governance/phase1.py +77 -0
  86. traceforge/governance/pii.py +276 -0
  87. traceforge/governance/pipeline.py +840 -0
  88. traceforge/governance/registry.py +110 -0
  89. traceforge/governance/results.py +183 -0
  90. traceforge/governance/risk_wrapper.py +113 -0
  91. traceforge/governance/rules.py +368 -0
  92. traceforge/governance/scorer.py +262 -0
  93. traceforge/governance/shield.py +318 -0
  94. traceforge/governance/state.py +466 -0
  95. traceforge/governance/types.py +176 -0
  96. traceforge/mappings/__init__.py +1 -0
  97. traceforge/mappings/aider.yaml +216 -0
  98. traceforge/mappings/aider_markdown.yaml +113 -0
  99. traceforge/mappings/amazonq.yaml +56 -0
  100. traceforge/mappings/antigravity.yaml +88 -0
  101. traceforge/mappings/claude.yaml +93 -0
  102. traceforge/mappings/cline.yaml +286 -0
  103. traceforge/mappings/codex.yaml +158 -0
  104. traceforge/mappings/continue_dev.yaml +57 -0
  105. traceforge/mappings/copilot.yaml +266 -0
  106. traceforge/mappings/copilot_markdown.yaml +72 -0
  107. traceforge/mappings/copilot_vscode.yaml +181 -0
  108. traceforge/mappings/crewai.yaml +592 -0
  109. traceforge/mappings/goose.yaml +128 -0
  110. traceforge/mappings/langgraph.yaml +165 -0
  111. traceforge/mappings/maf.yaml +90 -0
  112. traceforge/mappings/maf_transcript.yaml +99 -0
  113. traceforge/mappings/openai_agents.yaml +144 -0
  114. traceforge/mappings/opencode.yaml +473 -0
  115. traceforge/mappings/openhands.yaml +320 -0
  116. traceforge/mappings/pydantic_ai.yaml +183 -0
  117. traceforge/mappings/smolagents.yaml +89 -0
  118. traceforge/mappings/sweagent.yaml +82 -0
  119. traceforge/migrations/__init__.py +1 -0
  120. traceforge/migrations/env.py +60 -0
  121. traceforge/migrations/models.py +145 -0
  122. traceforge/migrations/runner.py +44 -0
  123. traceforge/migrations/script.py.mako +25 -0
  124. traceforge/migrations/versions/0001_initial.py +176 -0
  125. traceforge/migrations/versions/__init__.py +4 -0
  126. traceforge/models.py +29 -0
  127. traceforge/parsers/__init__.py +21 -0
  128. traceforge/parsers/aider.py +416 -0
  129. traceforge/parsers/base.py +226 -0
  130. traceforge/parsers/copilot.py +314 -0
  131. traceforge/phase/__init__.py +50 -0
  132. traceforge/phase/data/phase-model.joblib +0 -0
  133. traceforge/phase/data/potion-base-8M/README.md +99 -0
  134. traceforge/phase/data/potion-base-8M/config.json +13 -0
  135. traceforge/phase/data/potion-base-8M/model.safetensors +0 -0
  136. traceforge/phase/data/potion-base-8M/modules.json +14 -0
  137. traceforge/phase/data/potion-base-8M/tokenizer.json +1 -0
  138. traceforge/phase/event_rows.py +107 -0
  139. traceforge/phase/features.py +468 -0
  140. traceforge/phase/inference.py +279 -0
  141. traceforge/phase/inferencer.py +171 -0
  142. traceforge/phase/segmentation.py +258 -0
  143. traceforge/pipeline.py +891 -0
  144. traceforge/preprocessors/__init__.py +34 -0
  145. traceforge/preprocessors/amazonq.py +224 -0
  146. traceforge/preprocessors/antigravity.py +116 -0
  147. traceforge/preprocessors/claude.py +95 -0
  148. traceforge/preprocessors/cline.py +36 -0
  149. traceforge/preprocessors/codex.py +311 -0
  150. traceforge/preprocessors/continue_dev.py +119 -0
  151. traceforge/preprocessors/copilot_vscode.py +171 -0
  152. traceforge/preprocessors/goose.py +156 -0
  153. traceforge/preprocessors/maf_transcript.py +84 -0
  154. traceforge/preprocessors/openai_agents.py +86 -0
  155. traceforge/preprocessors/opencode.py +85 -0
  156. traceforge/preprocessors/openhands.py +36 -0
  157. traceforge/preprocessors/pydantic_ai.py +62 -0
  158. traceforge/preprocessors/registry.py +24 -0
  159. traceforge/preprocessors/smolagents.py +90 -0
  160. traceforge/py.typed +0 -0
  161. traceforge/sdk/__init__.py +59 -0
  162. traceforge/sdk/gate_policy.py +63 -0
  163. traceforge/sdk/gate_types.py +140 -0
  164. traceforge/sdk/pipeline.py +265 -0
  165. traceforge/sdk/verdict.py +81 -0
  166. traceforge/sinks/__init__.py +23 -0
  167. traceforge/sinks/base.py +95 -0
  168. traceforge/sinks/callback.py +132 -0
  169. traceforge/sinks/console.py +112 -0
  170. traceforge/sinks/factory.py +94 -0
  171. traceforge/sinks/jsonl.py +125 -0
  172. traceforge/sinks/otel_exporter.py +212 -0
  173. traceforge/sinks/parquet.py +260 -0
  174. traceforge/sinks/s3.py +206 -0
  175. traceforge/sinks/sqlite_output.py +234 -0
  176. traceforge/sinks/webhook.py +136 -0
  177. traceforge/sources/__init__.py +18 -0
  178. traceforge/sources/auto_detect.py +173 -0
  179. traceforge/sources/base.py +45 -0
  180. traceforge/sources/file_poll.py +136 -0
  181. traceforge/sources/file_watch.py +221 -0
  182. traceforge/sources/http_poll.py +141 -0
  183. traceforge/sources/replay.py +63 -0
  184. traceforge/sources/sqlite.py +187 -0
  185. traceforge/sources/sse.py +198 -0
  186. traceforge/telemetry/__init__.py +192 -0
  187. traceforge/title/__init__.py +23 -0
  188. traceforge/title/_resolve.py +79 -0
  189. traceforge/title/context.py +295 -0
  190. traceforge/title/data/boilerplate_files.json +14 -0
  191. traceforge/title/heuristics.py +429 -0
  192. traceforge/title/hygiene.py +90 -0
  193. traceforge/title/inference.py +314 -0
  194. traceforge/title/inferencer.py +477 -0
  195. traceforge/title/naming.py +398 -0
  196. traceforge/trace.py +291 -0
  197. traceforge/tracking/__init__.py +30 -0
  198. traceforge/tracking/models.py +115 -0
  199. traceforge/tracking/phase_tracker.py +288 -0
  200. traceforge/types.py +315 -0
  201. traceforge_toolkit-0.1.0.dist-info/METADATA +188 -0
  202. traceforge_toolkit-0.1.0.dist-info/RECORD +205 -0
  203. traceforge_toolkit-0.1.0.dist-info/WHEEL +4 -0
  204. traceforge_toolkit-0.1.0.dist-info/entry_points.txt +2 -0
  205. traceforge_toolkit-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,266 @@
1
+ """Universal classification dimensions — domain-agnostic root types.
2
+
3
+ These enums define the abstract roots of each classification dimension.
4
+ Domain plugins (like the built-in coding plugin) extend these hierarchically
5
+ using dot-path subtypes (e.g., "validator.linter" extends "validator").
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass
11
+ from enum import StrEnum
12
+ from typing import Any
13
+
14
+
15
+ # ── Semantic classification dimensions ──
16
+
17
+
18
+ class Mechanism(StrEnum):
19
+ """Primary resource domain the tool operates in.
20
+
21
+ Answers: "What kind of system resource does this tool interact with?"
22
+ NOT "how does the agent invoke it" (all tools are invoked via tool calls).
23
+ Domain plugins extend with dot-path subtypes (e.g., "process.shell").
24
+ """
25
+
26
+ FILESYSTEM = "filesystem" # Direct filesystem access (read/write/search files)
27
+ PROCESS = "process" # Spawns or interacts with OS processes
28
+ NETWORK = "network" # Makes network requests (HTTP, WebSocket, etc.)
29
+ DATABASE = "database" # Queries or mutates a database
30
+ DELEGATION = "delegation" # Delegates work to another agent or system
31
+ COMMUNICATION = "communication" # Exchanges messages (user or system)
32
+ UNKNOWN = "unknown" # Tool mechanism could not be determined
33
+
34
+
35
+ class Effect(StrEnum):
36
+ """Observable impact on state outside the agent.
37
+
38
+ Use None/absent on Classification when the effect cannot be determined
39
+ statically (e.g., a shell command whose behavior depends on arguments).
40
+ """
41
+
42
+ READ_ONLY = "read_only" # No external state change; pure observation
43
+ MUTATING = "mutating" # Changes external state (files, DB, services)
44
+ DESTRUCTIVE = "destructive" # Irreversible state change (delete, drop, rm -rf)
45
+
46
+
47
+ # Precedence for aggregating compound effects (highest wins)
48
+ EFFECT_PRECEDENCE: dict[str, int] = {
49
+ Effect.READ_ONLY: 1,
50
+ Effect.MUTATING: 2,
51
+ Effect.DESTRUCTIVE: 3,
52
+ }
53
+
54
+
55
+ class Scope(StrEnum):
56
+ """What is being operated on — the subject matter domain.
57
+
58
+ Scopes identify the TYPE of thing being touched, not the specific instance.
59
+ Domain plugins extend with dot-paths (e.g., "artifact.source_code").
60
+ """
61
+
62
+ ARTIFACT = "artifact" # A produced/maintained file or object (code, docs, images)
63
+ STATE = "state" # Runtime/operational state (processes, deployments, sessions)
64
+ DATA = "data" # Application-level data (user records, logs, metrics)
65
+ CONFIGURATION = "configuration" # Settings that control behavior (env vars, configs)
66
+ KNOWLEDGE = "knowledge" # Reference information (APIs, specs, documentation)
67
+ IDENTITY = "identity" # Auth/identity artifacts (keys, tokens, certs)
68
+ MESSAGE = "message" # Communication payloads (chat messages, notifications)
69
+
70
+
71
+ class Role(StrEnum):
72
+ """What archetype of tool is performing this action.
73
+
74
+ Roles describe the tool's PURPOSE, not its implementation.
75
+ A tool's role is stable across invocations (a linter is always a validator).
76
+ """
77
+
78
+ VALIDATOR = "validator" # Checks correctness without changing anything
79
+ RETRIEVER = "retriever" # Finds and returns existing information
80
+ TRANSFORMER = "transformer" # Converts input to a different form (compile, format, bundle)
81
+ GENERATOR = "generator" # Produces new content from specifications
82
+ MODIFIER = "modifier" # Makes targeted changes to existing content
83
+ EXECUTOR = "executor" # Runs code/commands as a side effect
84
+ COMMUNICATOR = "communicator" # Exchanges messages with humans or systems
85
+ ORCHESTRATOR = "orchestrator" # Coordinates other tools or workflows
86
+ OBSERVER = "observer" # Monitors/inspects without changing state (debug, profile)
87
+ PERSISTENCE = "persistence" # Manages durable storage (VCS, DB, cache)
88
+
89
+
90
+ class Action(StrEnum):
91
+ """The abstract operation being performed — the verb.
92
+
93
+ Actions are WHAT is done, independent of HOW (mechanism) or BY WHOM (role).
94
+ Domain plugins extend with dot-paths (e.g., "validate.lint").
95
+ """
96
+
97
+ VALIDATE = "validate" # Check correctness, report pass/fail
98
+ RETRIEVE = "retrieve" # Fetch existing data from a source
99
+ TRANSFORM = "transform" # Convert data from one form to another
100
+ GENERATE = "generate" # Create new content that didn't exist
101
+ EXECUTE = "execute" # Run a process for its side effects
102
+ DELIVER = "deliver" # Send/push data to an external destination
103
+ CONFIGURE = "configure" # Set up or change system configuration
104
+ ANALYZE = "analyze" # Inspect data to produce insights (not retrieve)
105
+ PERSIST = "persist" # Save data durably (commit, write, store)
106
+ MODIFY = "modify" # Change existing content in-place
107
+ REMOVE = "remove" # Delete or tear down something
108
+
109
+
110
+ class Capability(StrEnum):
111
+ """What system access the action requires — the permission model.
112
+
113
+ Capabilities are cumulative (a tool may need multiple).
114
+ Used for policy/gating decisions (e.g., "this action needs network access").
115
+ """
116
+
117
+ FILESYSTEM_READ = "filesystem_read" # Read files from disk
118
+ FILESYSTEM_WRITE = "filesystem_write" # Write/create/delete files on disk
119
+ NETWORK_INBOUND = "network_inbound" # Accept incoming connections
120
+ NETWORK_OUTBOUND = "network_outbound" # Make outgoing requests
121
+ SUBPROCESS = "subprocess" # Spawn child processes
122
+ USES_CREDENTIALS = "uses_credentials" # Accesses secrets/tokens
123
+ ELEVATED_PRIVILEGE = "elevated_privilege" # Requires sudo/admin
124
+ HUMAN_INTERACTION = "human_interaction" # Requires human response
125
+
126
+
127
+ class Structure(StrEnum):
128
+ """Compositional properties of the invocation — how steps are arranged.
129
+
130
+ Describes the structural pattern of the operation, not its content.
131
+ """
132
+
133
+ SEQUENTIAL = "sequential" # Steps execute one after another
134
+ PARALLEL = "parallel" # Steps execute concurrently
135
+ CONDITIONAL = "conditional" # Execution depends on a condition (if/then)
136
+ INTERACTIVE = "interactive" # Requires back-and-forth interaction
137
+
138
+
139
+ @dataclass(frozen=True)
140
+ class PhaseSegment:
141
+ """One phase's contribution to a compound classification.
142
+
143
+ Groups the actions, scopes, and roles that together produced this phase.
144
+ Preserves the pairing so downstream consumers know which labels belong together.
145
+ """
146
+
147
+ phase: str
148
+ actions: frozenset[str] = frozenset()
149
+ scopes: frozenset[str] = frozenset()
150
+ roles: frozenset[str] = frozenset()
151
+
152
+
153
+ @dataclass(frozen=True)
154
+ class Classification:
155
+ """Multi-dimensional classification of an agent action.
156
+
157
+ All dimension values are dot-path strings from registered enums.
158
+ Use the registry to validate values and query hierarchy.
159
+
160
+ For compound commands, `phase_map` groups labels by their derived phase —
161
+ each segment contains the actions/scopes/roles that produced that phase.
162
+ The top-level `action`, `scope`, `role` sets are the aggregate union
163
+ for quick flat queries.
164
+ """
165
+
166
+ mechanism: str
167
+ effect: str | None = None
168
+ scope: frozenset[str] = frozenset()
169
+ role: frozenset[str] = frozenset()
170
+ action: frozenset[str] = frozenset()
171
+ capability: frozenset[str] = frozenset()
172
+ structure: frozenset[str] = frozenset()
173
+ source_labels: frozenset[str] = frozenset()
174
+ shell_dialect: str | None = None
175
+ binaries: tuple[str, ...] = ()
176
+ phase_map: tuple[PhaseSegment, ...] = ()
177
+
178
+ def to_dict(self) -> dict[str, Any]:
179
+ """Serialize to a JSON-safe dictionary."""
180
+ d: dict[str, Any] = {
181
+ "mechanism": self.mechanism,
182
+ }
183
+ if self.effect is not None:
184
+ d["effect"] = self.effect
185
+ if self.scope:
186
+ d["scope"] = sorted(self.scope)
187
+ if self.role:
188
+ d["role"] = sorted(self.role)
189
+ if self.action:
190
+ d["action"] = sorted(self.action)
191
+ if self.capability:
192
+ d["capability"] = sorted(self.capability)
193
+ if self.structure:
194
+ d["structure"] = sorted(self.structure)
195
+ if self.source_labels:
196
+ d["source_labels"] = sorted(self.source_labels)
197
+ if self.shell_dialect:
198
+ d["shell_dialect"] = self.shell_dialect
199
+ if self.binaries:
200
+ d["binaries"] = list(self.binaries)
201
+ if self.phase_map:
202
+ d["phase_map"] = [
203
+ {
204
+ "phase": seg.phase,
205
+ "actions": sorted(seg.actions),
206
+ "scopes": sorted(seg.scopes),
207
+ "roles": sorted(seg.roles),
208
+ }
209
+ for seg in self.phase_map
210
+ ]
211
+ return d
212
+
213
+ @classmethod
214
+ def from_dict(cls, d: dict[str, Any]) -> Classification:
215
+ """Deserialize from a dictionary."""
216
+ phase_map_raw = d.get("phase_map") or ()
217
+ phase_map = tuple(
218
+ PhaseSegment(
219
+ phase=seg["phase"],
220
+ actions=frozenset(seg.get("actions") or ()),
221
+ scopes=frozenset(seg.get("scopes") or ()),
222
+ roles=frozenset(seg.get("roles") or ()),
223
+ )
224
+ for seg in phase_map_raw
225
+ if isinstance(seg, dict)
226
+ )
227
+ return cls(
228
+ mechanism=d["mechanism"],
229
+ effect=d.get("effect"),
230
+ scope=frozenset(d.get("scope") or ()),
231
+ role=frozenset(d.get("role") or ()),
232
+ action=frozenset(d.get("action") or ()),
233
+ capability=frozenset(d.get("capability") or ()),
234
+ structure=frozenset(d.get("structure") or ()),
235
+ source_labels=frozenset(d.get("source_labels") or ()),
236
+ shell_dialect=d.get("shell_dialect"),
237
+ binaries=tuple(d.get("binaries") or ()),
238
+ phase_map=phase_map,
239
+ )
240
+
241
+ def has_role(self, ancestor: str) -> bool:
242
+ """Check if any role matches or descends from ancestor."""
243
+ return any(r == ancestor or r.startswith(ancestor + ".") for r in self.role)
244
+
245
+ def has_action(self, ancestor: str) -> bool:
246
+ """Check if any action matches or descends from ancestor."""
247
+ return any(a == ancestor or a.startswith(ancestor + ".") for a in self.action)
248
+
249
+ def has_scope(self, ancestor: str) -> bool:
250
+ """Check if any scope matches or descends from ancestor."""
251
+ return any(s == ancestor or s.startswith(ancestor + ".") for s in self.scope)
252
+
253
+
254
+ def aggregate_effect(*effects: str) -> str | None:
255
+ """Return the highest-precedence effect from a set of effects.
256
+
257
+ Returns None if no effects are provided or all are unrecognized.
258
+ """
259
+ best: str | None = None
260
+ best_p = 0
261
+ for e in effects:
262
+ p = EFFECT_PRECEDENCE.get(e, 0)
263
+ if p > best_p:
264
+ best_p = p
265
+ best = e
266
+ return best
@@ -0,0 +1,358 @@
1
+ # Binary metadata - role and default effect for known CLI binaries.
2
+ # Used by shell classification to determine effect and role when
3
+ # no specific rule matches.
4
+ #
5
+ # IMPORTANT: role values MUST match CodingRole enum values in coding.py.
6
+ # Valid prefixes: validator.*, transformer.*, generator.*, executor.*,
7
+ # orchestrator.*, observer.*, retriever.*, modifier.*, persistence.*,
8
+ # communicator.*
9
+
10
+ binary_info:
11
+ # --- Test runners ---
12
+ bats: { role: validator.test_runner, default_effect: read_only }
13
+ invoke-pester: { role: validator.test_runner, default_effect: read_only }
14
+ jest: { role: validator.test_runner, default_effect: read_only }
15
+ mocha: { role: validator.test_runner, default_effect: read_only }
16
+ nox: { role: validator.test_runner, default_effect: null, network: true }
17
+ pest: { role: validator.test_runner, default_effect: read_only }
18
+ phpunit: { role: validator.test_runner, default_effect: read_only }
19
+ playwright: { role: validator.test_runner, default_effect: read_only }
20
+ pytest: { role: validator.test_runner, default_effect: read_only }
21
+ rspec: { role: validator.test_runner, default_effect: read_only }
22
+ tox: { role: validator.test_runner, default_effect: null, network: true }
23
+ vitest: { role: validator.test_runner, default_effect: read_only }
24
+
25
+ # --- Type checkers ---
26
+ mypy: { role: validator.type_checker, default_effect: read_only }
27
+ pyright: { role: validator.type_checker, default_effect: read_only }
28
+
29
+ # --- Linters ---
30
+ clippy: { role: validator.linter, default_effect: read_only }
31
+ eslint: { role: validator.linter, default_effect: read_only }
32
+ flake8: { role: validator.linter, default_effect: read_only }
33
+ golangci-lint: { role: validator.linter, default_effect: read_only }
34
+ invoke-scriptanalyzer: { role: validator.linter, default_effect: read_only }
35
+ pylint: { role: validator.linter, default_effect: read_only }
36
+ rubocop: { role: validator.linter, default_effect: read_only }
37
+ ruff: { role: validator.linter, default_effect: read_only }
38
+
39
+ # --- Security scanners ---
40
+ bandit: { role: validator.security_scanner, default_effect: read_only }
41
+ safety: { role: validator.security_scanner, default_effect: read_only, network: true }
42
+ semgrep: { role: validator.security_scanner, default_effect: read_only }
43
+ snyk: { role: validator.security_scanner, default_effect: read_only, network: true }
44
+ trivy: { role: validator.security_scanner, default_effect: read_only }
45
+
46
+ # --- Build checkers ---
47
+ bazel: { role: validator.build_checker, default_effect: null, network: true }
48
+ build-module: { role: validator.build_checker, default_effect: mutating }
49
+ cmake: { role: validator.build_checker, default_effect: mutating }
50
+ invoke-build: { role: validator.build_checker, default_effect: mutating }
51
+ ninja: { role: validator.build_checker, default_effect: mutating }
52
+
53
+ # --- Formatters ---
54
+ black: { role: transformer.formatter, default_effect: mutating }
55
+ prettier: { role: transformer.formatter, default_effect: read_only }
56
+
57
+ # --- Compilers ---
58
+ clang: { role: transformer.compiler, default_effect: mutating }
59
+ clang++: { role: transformer.compiler, default_effect: mutating }
60
+ g++: { role: transformer.compiler, default_effect: mutating }
61
+ gcc: { role: transformer.compiler, default_effect: mutating }
62
+ javac: { role: transformer.compiler, default_effect: mutating }
63
+ rustc: { role: transformer.compiler, default_effect: mutating }
64
+
65
+ # --- Bundlers ---
66
+ vite: { role: transformer.bundler, default_effect: null }
67
+ webpack: { role: transformer.bundler, default_effect: mutating }
68
+
69
+ # --- Transpilers / encoding ---
70
+ b64encode: { role: transformer.transpiler, default_effect: read_only }
71
+ base64: { role: transformer.transpiler, default_effect: read_only }
72
+ gpg: { role: transformer.transpiler, default_effect: null }
73
+ hexdump: { role: transformer.transpiler, default_effect: read_only }
74
+ od: { role: transformer.transpiler, default_effect: read_only }
75
+ openssl: { role: transformer.transpiler, default_effect: null }
76
+ tsc: { role: transformer.transpiler, default_effect: null }
77
+ xxd: { role: transformer.transpiler, default_effect: read_only }
78
+
79
+ # --- Package managers ---
80
+ apt: { role: orchestrator.package_manager, default_effect: mutating, network: true }
81
+ apt-get: { role: orchestrator.package_manager, default_effect: mutating, network: true }
82
+ asdf: { role: orchestrator.package_manager, default_effect: mutating }
83
+ brew: { role: orchestrator.package_manager, default_effect: mutating, network: true }
84
+ choco: { role: orchestrator.package_manager, default_effect: mutating, network: true }
85
+ conda: { role: orchestrator.package_manager, default_effect: null, network: true }
86
+ dnf: { role: orchestrator.package_manager, default_effect: mutating, network: true }
87
+ dpkg: { role: orchestrator.package_manager, default_effect: mutating }
88
+ emerge: { role: orchestrator.package_manager, default_effect: mutating, network: true }
89
+ flatpak: { role: orchestrator.package_manager, default_effect: mutating, network: true }
90
+ fnm: { role: orchestrator.package_manager, default_effect: mutating }
91
+ helm: { role: orchestrator.package_manager, default_effect: null, network: true }
92
+ install-module: { role: orchestrator.package_manager, default_effect: mutating, network: true }
93
+ install-package: { role: orchestrator.package_manager, default_effect: mutating, network: true }
94
+ install-psresource: { role: orchestrator.package_manager, default_effect: mutating, network: true }
95
+ mise: { role: orchestrator.package_manager, default_effect: mutating }
96
+ nix: { role: orchestrator.package_manager, default_effect: null, network: true }
97
+ nvm: { role: orchestrator.package_manager, default_effect: mutating }
98
+ pacman: { role: orchestrator.package_manager, default_effect: mutating, network: true }
99
+ pip: { role: orchestrator.package_manager, default_effect: mutating, network: true }
100
+ pip-compile: { role: orchestrator.package_manager, default_effect: mutating }
101
+ pip3: { role: orchestrator.package_manager, default_effect: mutating, network: true }
102
+ pipx: { role: orchestrator.package_manager, default_effect: mutating, network: true }
103
+ poetry: { role: orchestrator.package_manager, default_effect: mutating, network: true }
104
+ pyenv: { role: orchestrator.package_manager, default_effect: mutating }
105
+ rbenv: { role: orchestrator.package_manager, default_effect: mutating }
106
+ register-psrepository: { role: orchestrator.package_manager, default_effect: mutating, network: true }
107
+ rpm: { role: orchestrator.package_manager, default_effect: mutating }
108
+ rtx: { role: orchestrator.package_manager, default_effect: mutating }
109
+ rustup: { role: orchestrator.package_manager, default_effect: mutating, network: true }
110
+ scoop: { role: orchestrator.package_manager, default_effect: mutating, network: true }
111
+ snap: { role: orchestrator.package_manager, default_effect: mutating, network: true }
112
+ update-module: { role: orchestrator.package_manager, default_effect: mutating, network: true }
113
+ uv: { role: orchestrator.package_manager, default_effect: mutating, network: true }
114
+ virtualenv: { role: orchestrator.package_manager, default_effect: mutating }
115
+ winget: { role: orchestrator.package_manager, default_effect: mutating, network: true }
116
+ yum: { role: orchestrator.package_manager, default_effect: mutating, network: true }
117
+ zypper: { role: orchestrator.package_manager, default_effect: mutating, network: true }
118
+
119
+ # --- Task runners ---
120
+ ansible: { role: orchestrator.task_runner, default_effect: null, network: true }
121
+ bun: { role: orchestrator.task_runner, default_effect: null, network: true }
122
+ bunx: { role: orchestrator.task_runner, default_effect: null, network: true }
123
+ cargo: { role: orchestrator.task_runner, default_effect: null, network: true }
124
+ dart: { role: orchestrator.task_runner, default_effect: null, network: true }
125
+ deno: { role: orchestrator.task_runner, default_effect: null, network: true }
126
+ dotnet: { role: orchestrator.task_runner, default_effect: null, network: true }
127
+ go: { role: orchestrator.task_runner, default_effect: null, network: true }
128
+ gradle: { role: orchestrator.task_runner, default_effect: null, network: true }
129
+ make: { role: orchestrator.task_runner, default_effect: null }
130
+ mvn: { role: orchestrator.task_runner, default_effect: null, network: true }
131
+ npm: { role: orchestrator.task_runner, default_effect: null, network: true }
132
+ npx: { role: orchestrator.task_runner, default_effect: null, network: true }
133
+ pnpm: { role: orchestrator.task_runner, default_effect: null, network: true }
134
+ pulumi: { role: orchestrator.task_runner, default_effect: null, network: true }
135
+ swift: { role: orchestrator.task_runner, default_effect: null, network: true }
136
+ terraform: { role: orchestrator.task_runner, default_effect: null, network: true }
137
+ tofu: { role: orchestrator.task_runner, default_effect: null, network: true }
138
+ twine: { role: orchestrator.task_runner, default_effect: null, network: true }
139
+ yarn: { role: orchestrator.task_runner, default_effect: null, network: true }
140
+
141
+ # --- Container runtimes ---
142
+ docker: { role: executor.container_runtime, default_effect: null, network: true }
143
+ docker-compose: { role: executor.container_runtime, default_effect: null, network: true }
144
+ eksctl: { role: executor.container_runtime, default_effect: null, network: true }
145
+ kind: { role: executor.container_runtime, default_effect: null, network: true }
146
+ kubectl: { role: executor.container_runtime, default_effect: null, network: true }
147
+ minikube: { role: executor.container_runtime, default_effect: null, network: true }
148
+ podman: { role: executor.container_runtime, default_effect: null, network: true }
149
+ vagrant: { role: executor.container_runtime, default_effect: null, network: true }
150
+
151
+ # --- Script runners / process control ---
152
+ bash: { role: executor.script_runner, default_effect: null }
153
+ crontab: { role: executor.script_runner, default_effect: mutating }
154
+ iptables: { role: executor.script_runner, default_effect: null, network: true }
155
+ kill: { role: executor.script_runner, default_effect: destructive, destructive: true }
156
+ killall: { role: executor.script_runner, default_effect: destructive, destructive: true }
157
+ pkill: { role: executor.script_runner, default_effect: destructive, destructive: true }
158
+ mount: { role: executor.script_runner, default_effect: mutating }
159
+ node: { role: executor.script_runner, default_effect: null }
160
+ perl: { role: executor.script_runner, default_effect: null }
161
+ php: { role: executor.script_runner, default_effect: null, network: true }
162
+ python: { role: executor.script_runner, default_effect: null }
163
+ python3: { role: executor.script_runner, default_effect: null }
164
+ restart-service: { role: executor.script_runner, default_effect: mutating }
165
+ ruby: { role: executor.script_runner, default_effect: null }
166
+ sh: { role: executor.script_runner, default_effect: null }
167
+ ssh: { role: executor.script_runner, default_effect: null, network: true }
168
+ start-process: { role: executor.script_runner, default_effect: mutating }
169
+ start-service: { role: executor.script_runner, default_effect: mutating }
170
+ stop-process: { role: executor.script_runner, default_effect: destructive, destructive: true }
171
+ stop-service: { role: executor.script_runner, default_effect: mutating }
172
+ sudo: { role: executor.script_runner, default_effect: null }
173
+ systemctl: { role: executor.script_runner, default_effect: null }
174
+ umount: { role: executor.script_runner, default_effect: mutating }
175
+ xargs: { role: executor.script_runner, default_effect: null }
176
+ zsh: { role: executor.script_runner, default_effect: null }
177
+
178
+ # --- Version control ---
179
+ git: { role: persistence.version_control, default_effect: null }
180
+ hg: { role: persistence.version_control, default_effect: null, network: true }
181
+ svn: { role: persistence.version_control, default_effect: null, network: true }
182
+
183
+ # --- Databases ---
184
+ mongosh: { role: persistence.database, default_effect: null, network: true }
185
+ mysql: { role: persistence.database, default_effect: null, network: true }
186
+ psql: { role: persistence.database, default_effect: null, network: true }
187
+ redis-cli: { role: persistence.cache, default_effect: null, network: true }
188
+ sqlite3: { role: persistence.database, default_effect: null }
189
+
190
+ # --- API clients / network ---
191
+ aws: { role: retriever.api_client, default_effect: null, network: true }
192
+ aws-vault: { role: retriever.api_client, default_effect: null, network: true }
193
+ az: { role: retriever.api_client, default_effect: null, network: true }
194
+ azd: { role: retriever.api_client, default_effect: null, network: true }
195
+ copilot-cli: { role: retriever.api_client, default_effect: null, network: true }
196
+ curl: { role: retriever.api_client, default_effect: read_only, network: true }
197
+ dig: { role: retriever.api_client, default_effect: read_only, network: true }
198
+ doctl: { role: retriever.api_client, default_effect: null, network: true }
199
+ ftp: { role: retriever.api_client, default_effect: null, network: true }
200
+ gcloud: { role: retriever.api_client, default_effect: null, network: true }
201
+ gsutil: { role: retriever.api_client, default_effect: null, network: true }
202
+ gh: { role: retriever.api_client, default_effect: null, network: true }
203
+ oci: { role: retriever.api_client, default_effect: null, network: true }
204
+ sam: { role: retriever.api_client, default_effect: null, network: true }
205
+ invoke-restmethod: { role: retriever.api_client, default_effect: null, network: true }
206
+ invoke-webrequest: { role: retriever.api_client, default_effect: null, network: true }
207
+ nc: { role: retriever.api_client, default_effect: null, network: true }
208
+ ncat: { role: retriever.api_client, default_effect: null, network: true }
209
+ nslookup: { role: retriever.api_client, default_effect: read_only, network: true }
210
+ ping: { role: retriever.api_client, default_effect: read_only, network: true }
211
+ socat: { role: retriever.api_client, default_effect: null, network: true }
212
+ telnet: { role: retriever.api_client, default_effect: null, network: true }
213
+ test-connection: { role: retriever.api_client, default_effect: read_only, network: true }
214
+ test-netconnection: { role: retriever.api_client, default_effect: read_only, network: true }
215
+ traceroute: { role: retriever.api_client, default_effect: read_only, network: true }
216
+ wget: { role: retriever.api_client, default_effect: mutating, network: true }
217
+
218
+ # --- File browsers / system info ---
219
+ bat: { role: retriever.file_browser, default_effect: read_only }
220
+ cat: { role: retriever.file_browser, default_effect: read_only }
221
+ date: { role: retriever.file_browser, default_effect: read_only }
222
+ df: { role: retriever.file_browser, default_effect: read_only }
223
+ dir: { role: retriever.file_browser, default_effect: read_only }
224
+ du: { role: retriever.file_browser, default_effect: read_only }
225
+ env: { role: retriever.file_browser, default_effect: read_only }
226
+ exa: { role: retriever.file_browser, default_effect: read_only }
227
+ eza: { role: retriever.file_browser, default_effect: read_only }
228
+ fd: { role: retriever.file_browser, default_effect: read_only }
229
+ fdfind: { role: retriever.file_browser, default_effect: read_only }
230
+ find: { role: retriever.file_browser, default_effect: read_only }
231
+ format-list: { role: retriever.file_browser, default_effect: read_only }
232
+ format-table: { role: retriever.file_browser, default_effect: read_only }
233
+ free: { role: retriever.file_browser, default_effect: read_only }
234
+ get-childitem: { role: retriever.file_browser, default_effect: read_only }
235
+ get-command: { role: retriever.file_browser, default_effect: read_only }
236
+ get-content: { role: retriever.file_browser, default_effect: read_only }
237
+ get-help: { role: retriever.file_browser, default_effect: read_only }
238
+ get-item: { role: retriever.file_browser, default_effect: read_only }
239
+ get-itemproperty: { role: retriever.file_browser, default_effect: read_only }
240
+ get-module: { role: retriever.file_browser, default_effect: read_only }
241
+ get-process: { role: retriever.file_browser, default_effect: read_only }
242
+ get-service: { role: retriever.file_browser, default_effect: read_only }
243
+ get-variable: { role: retriever.file_browser, default_effect: read_only }
244
+ head: { role: retriever.file_browser, default_effect: read_only }
245
+ hostname: { role: retriever.file_browser, default_effect: read_only }
246
+ less: { role: retriever.file_browser, default_effect: read_only }
247
+ ll: { role: retriever.file_browser, default_effect: read_only }
248
+ ls: { role: retriever.file_browser, default_effect: read_only }
249
+ lsd: { role: retriever.file_browser, default_effect: read_only }
250
+ man: { role: retriever.file_browser, default_effect: read_only }
251
+ more: { role: retriever.file_browser, default_effect: read_only }
252
+ netstat: { role: retriever.file_browser, default_effect: read_only }
253
+ printenv: { role: retriever.file_browser, default_effect: read_only }
254
+ ps: { role: retriever.file_browser, default_effect: read_only }
255
+ pwd: { role: retriever.file_browser, default_effect: read_only }
256
+ set: { role: retriever.file_browser, default_effect: null }
257
+ ss: { role: retriever.file_browser, default_effect: read_only }
258
+ tail: { role: retriever.file_browser, default_effect: read_only }
259
+ test-path: { role: retriever.file_browser, default_effect: read_only }
260
+ tree: { role: retriever.file_browser, default_effect: read_only }
261
+ type: { role: retriever.file_browser, default_effect: read_only }
262
+ uname: { role: retriever.file_browser, default_effect: read_only }
263
+ uptime: { role: retriever.file_browser, default_effect: read_only }
264
+ where: { role: retriever.file_browser, default_effect: read_only }
265
+ whereis: { role: retriever.file_browser, default_effect: read_only }
266
+ which: { role: retriever.file_browser, default_effect: read_only }
267
+ whoami: { role: retriever.file_browser, default_effect: read_only }
268
+ write-host: { role: retriever.file_browser, default_effect: read_only }
269
+ write-output: { role: retriever.file_browser, default_effect: read_only }
270
+
271
+ # --- Search / text processing ---
272
+ ag: { role: retriever.search_index, default_effect: read_only }
273
+ awk: { role: retriever.search_index, default_effect: read_only }
274
+ comm: { role: retriever.search_index, default_effect: read_only }
275
+ cut: { role: retriever.search_index, default_effect: read_only }
276
+ diff: { role: retriever.search_index, default_effect: read_only }
277
+ egrep: { role: retriever.search_index, default_effect: read_only }
278
+ fgrep: { role: retriever.search_index, default_effect: read_only }
279
+ findstr: { role: retriever.search_index, default_effect: read_only }
280
+ gawk: { role: retriever.search_index, default_effect: read_only }
281
+ grep: { role: retriever.search_index, default_effect: read_only }
282
+ jq: { role: retriever.search_index, default_effect: read_only }
283
+ mawk: { role: retriever.search_index, default_effect: read_only }
284
+ measure-object: { role: retriever.search_index, default_effect: read_only }
285
+ nawk: { role: retriever.search_index, default_effect: read_only }
286
+ out-string: { role: retriever.search_index, default_effect: read_only }
287
+ paste: { role: retriever.search_index, default_effect: read_only }
288
+ rg: { role: retriever.search_index, default_effect: read_only }
289
+ ripgrep: { role: retriever.search_index, default_effect: read_only }
290
+ sed: { role: retriever.search_index, default_effect: read_only }
291
+ select-object: { role: retriever.search_index, default_effect: read_only }
292
+ select-string: { role: retriever.search_index, default_effect: read_only }
293
+ sort: { role: retriever.search_index, default_effect: read_only }
294
+ sort-object: { role: retriever.search_index, default_effect: read_only }
295
+ tr: { role: retriever.search_index, default_effect: read_only }
296
+ uniq: { role: retriever.search_index, default_effect: read_only }
297
+ wc: { role: retriever.search_index, default_effect: read_only }
298
+ where-object: { role: retriever.search_index, default_effect: read_only }
299
+ yq: { role: retriever.search_index, default_effect: read_only }
300
+
301
+ # --- Debuggers / profilers ---
302
+ gdb: { role: observer.debugger, default_effect: null }
303
+ lsof: { role: observer.debugger, default_effect: read_only }
304
+ ltrace: { role: observer.debugger, default_effect: read_only }
305
+ strace: { role: observer.debugger, default_effect: read_only }
306
+
307
+ # --- File editors / modifiers ---
308
+ add-content: { role: modifier.file_editor, default_effect: mutating }
309
+ bzip2: { role: modifier.file_editor, default_effect: null }
310
+ chgrp: { role: modifier.file_editor, default_effect: mutating }
311
+ chmod: { role: modifier.file_editor, default_effect: mutating }
312
+ chown: { role: modifier.file_editor, default_effect: mutating }
313
+ copy: { role: modifier.file_editor, default_effect: mutating }
314
+ copy-item: { role: modifier.file_editor, default_effect: mutating }
315
+ cp: { role: modifier.file_editor, default_effect: mutating }
316
+ cpio: { role: modifier.file_editor, default_effect: null }
317
+ dd: { role: modifier.file_editor, default_effect: destructive, destructive: true }
318
+ del: { role: modifier.file_editor, default_effect: destructive, destructive: true }
319
+ emacs: { role: modifier.file_editor, default_effect: mutating }
320
+ erase: { role: modifier.file_editor, default_effect: destructive, destructive: true }
321
+ gunzip: { role: modifier.file_editor, default_effect: null }
322
+ gzip: { role: modifier.file_editor, default_effect: null }
323
+ icacls: { role: modifier.file_editor, default_effect: mutating }
324
+ ln: { role: modifier.file_editor, default_effect: mutating }
325
+ mkdir: { role: modifier.file_editor, default_effect: mutating }
326
+ mkfs: { role: modifier.file_editor, default_effect: destructive, destructive: true }
327
+ mkfs.ext2: { role: modifier.file_editor, default_effect: destructive, destructive: true }
328
+ mkfs.ext3: { role: modifier.file_editor, default_effect: destructive, destructive: true }
329
+ mkfs.ext4: { role: modifier.file_editor, default_effect: destructive, destructive: true }
330
+ mkfs.xfs: { role: modifier.file_editor, default_effect: destructive, destructive: true }
331
+ mkfs.btrfs: { role: modifier.file_editor, default_effect: destructive, destructive: true }
332
+ mkfs.vfat: { role: modifier.file_editor, default_effect: destructive, destructive: true }
333
+ move: { role: modifier.file_editor, default_effect: mutating }
334
+ move-item: { role: modifier.file_editor, default_effect: mutating }
335
+ mv: { role: modifier.file_editor, default_effect: mutating }
336
+ nano: { role: modifier.file_editor, default_effect: mutating }
337
+ new-item: { role: modifier.file_editor, default_effect: mutating }
338
+ out-file: { role: modifier.file_editor, default_effect: mutating }
339
+ patch: { role: modifier.file_editor, default_effect: mutating }
340
+ rd: { role: modifier.file_editor, default_effect: destructive, destructive: true }
341
+ remove-item: { role: modifier.file_editor, default_effect: destructive, destructive: true }
342
+ rename: { role: modifier.file_editor, default_effect: mutating }
343
+ rename-item: { role: modifier.file_editor, default_effect: mutating }
344
+ rm: { role: modifier.file_editor, default_effect: destructive, destructive: true }
345
+ rmdir: { role: modifier.file_editor, default_effect: destructive, destructive: true }
346
+ rsync: { role: modifier.file_editor, default_effect: mutating, network: true }
347
+ scp: { role: modifier.file_editor, default_effect: mutating, network: true }
348
+ set-content: { role: modifier.file_editor, default_effect: mutating }
349
+ set-itemproperty: { role: modifier.file_editor, default_effect: mutating }
350
+ tar: { role: modifier.file_editor, default_effect: null }
351
+ tee: { role: modifier.file_editor, default_effect: mutating }
352
+ touch: { role: modifier.file_editor, default_effect: mutating }
353
+ truncate: { role: modifier.file_editor, default_effect: destructive, destructive: true }
354
+ unzip: { role: modifier.file_editor, default_effect: null }
355
+ vi: { role: modifier.file_editor, default_effect: mutating }
356
+ vim: { role: modifier.file_editor, default_effect: mutating }
357
+ xz: { role: modifier.file_editor, default_effect: null }
358
+ zip: { role: modifier.file_editor, default_effect: null }