xrefkit 0.3.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 (65) hide show
  1. xrefkit/__init__.py +5 -0
  2. xrefkit/__main__.py +5 -0
  3. xrefkit/catalog_cli.py +57 -0
  4. xrefkit/cli.py +71 -0
  5. xrefkit/contracts.py +297 -0
  6. xrefkit/ctx.py +160 -0
  7. xrefkit/dashboard.py +1220 -0
  8. xrefkit/discovery.py +85 -0
  9. xrefkit/gate.py +428 -0
  10. xrefkit/goalstate.py +555 -0
  11. xrefkit/hashing.py +18 -0
  12. xrefkit/import_skill.py +469 -0
  13. xrefkit/instance.py +133 -0
  14. xrefkit/loaders.py +77 -0
  15. xrefkit/mcp/__init__.py +26 -0
  16. xrefkit/mcp/audit.py +168 -0
  17. xrefkit/mcp/bootstrap.py +337 -0
  18. xrefkit/mcp/catalog.py +2638 -0
  19. xrefkit/mcp/cli.py +173 -0
  20. xrefkit/mcp/client_cache.py +356 -0
  21. xrefkit/mcp/context_registry.py +277 -0
  22. xrefkit/mcp/contracts.py +243 -0
  23. xrefkit/mcp/dist.py +234 -0
  24. xrefkit/mcp/ownership.py +246 -0
  25. xrefkit/mcp/repository.py +217 -0
  26. xrefkit/mcp/schemas.py +349 -0
  27. xrefkit/mcp/server.py +773 -0
  28. xrefkit/mcp/startup_contract_pack.py +154 -0
  29. xrefkit/mcp_tools.py +47 -0
  30. xrefkit/models/__init__.py +41 -0
  31. xrefkit/models/common.py +185 -0
  32. xrefkit/models/effective_bundle.py +131 -0
  33. xrefkit/models/local_manifest.py +217 -0
  34. xrefkit/models/package_manifest.py +126 -0
  35. xrefkit/models/run_log.py +276 -0
  36. xrefkit/models/server_config.py +160 -0
  37. xrefkit/models/skill_definition.py +131 -0
  38. xrefkit/operations_cli.py +670 -0
  39. xrefkit/ownership.py +276 -0
  40. xrefkit/packmeta.py +289 -0
  41. xrefkit/registry.py +334 -0
  42. xrefkit/resolver.py +252 -0
  43. xrefkit/resource_provider.py +187 -0
  44. xrefkit/resources/base/contracts.json +178 -0
  45. xrefkit/resources/base/current.json +6 -0
  46. xrefkit/resources/base/generations/7a682a5272907354/contracts.json +178 -0
  47. xrefkit/resources/base/generations/7a682a5272907354/model_body.md +22 -0
  48. xrefkit/resources/base/generations/9929294385ccb7b0/contracts.json +178 -0
  49. xrefkit/resources/base/generations/9929294385ccb7b0/model_body.md +22 -0
  50. xrefkit/resources/base/model_body.md +22 -0
  51. xrefkit/runlog.py +45 -0
  52. xrefkit/skillmeta.py +1034 -0
  53. xrefkit/skillrun.py +2381 -0
  54. xrefkit/structure_catalog.py +199 -0
  55. xrefkit/tools/__init__.py +119 -0
  56. xrefkit/tools/__main__.py +4 -0
  57. xrefkit/v2_cli.py +130 -0
  58. xrefkit/workspace.py +117 -0
  59. xrefkit/xref.py +1048 -0
  60. xrefkit-0.3.0.dist-info/METADATA +203 -0
  61. xrefkit-0.3.0.dist-info/RECORD +65 -0
  62. xrefkit-0.3.0.dist-info/WHEEL +5 -0
  63. xrefkit-0.3.0.dist-info/entry_points.txt +2 -0
  64. xrefkit-0.3.0.dist-info/licenses/LICENSE +21 -0
  65. xrefkit-0.3.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,670 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import sys
5
+
6
+ from xrefkit.xref import XrefConfig, cmd_xref
7
+
8
+
9
+ def _build_parser() -> argparse.ArgumentParser:
10
+ parser = argparse.ArgumentParser(prog="xrefkit", description="XRefKit control CLI")
11
+ subparsers = parser.add_subparsers(dest="command", required=True)
12
+
13
+ xref = subparsers.add_parser("xref", help="Stable cross-file links by ID")
14
+ xref_sub = xref.add_subparsers(dest="xref_cmd", required=True)
15
+
16
+ def add_common_config(p: argparse.ArgumentParser) -> None:
17
+ p.add_argument("--root", default=".", help="Project root (default: .)")
18
+ p.add_argument(
19
+ "--include",
20
+ nargs="*",
21
+ default=None,
22
+ help="Top-level folders to include (default: docs agent knowledge capabilities skills packs tools)",
23
+ )
24
+ p.add_argument(
25
+ "--exclude",
26
+ nargs="*",
27
+ default=None,
28
+ help="Folder names to exclude (default: .git .xref node_modules .venv venv)",
29
+ )
30
+
31
+ p_init = xref_sub.add_parser("init", help="Add missing XIDs to markdown files")
32
+ add_common_config(p_init)
33
+ p_init.add_argument("--dry-run", action="store_true", help="Show changes only")
34
+
35
+ p_check = xref_sub.add_parser("check", help="Validate XIDs and managed links")
36
+ add_common_config(p_check)
37
+ p_check.add_argument("--json", action="store_true", help="Emit machine-readable JSON")
38
+ p_check.add_argument(
39
+ "--review",
40
+ action="store_true",
41
+ help="Emit human review hints for XID-bearing docs (best-effort)",
42
+ )
43
+
44
+ p_rewrite = xref_sub.add_parser("rewrite", help="Rewrite managed links to correct paths")
45
+ add_common_config(p_rewrite)
46
+ p_rewrite.add_argument("--dry-run", action="store_true", help="Show changes only")
47
+
48
+ p_fix = xref_sub.add_parser("fix", help="Run init + rewrite + check in one command")
49
+ add_common_config(p_fix)
50
+ p_fix.add_argument("--dry-run", action="store_true", help="Show changes only")
51
+ p_fix.add_argument("--json", action="store_true", help="Emit machine-readable JSON")
52
+ p_fix.add_argument(
53
+ "--review",
54
+ action="store_true",
55
+ help="Include human review hints from check phase (best-effort)",
56
+ )
57
+
58
+ p_index = xref_sub.add_parser("index", help="Print XID -> path mapping")
59
+ add_common_config(p_index)
60
+ p_index.add_argument("--json", action="store_true", help="Emit JSON (default)")
61
+
62
+ p_search = xref_sub.add_parser("search", help="Search docs and return matching XIDs")
63
+ add_common_config(p_search)
64
+ p_search.add_argument("query", help="Substring or /regex/ (case-insensitive)")
65
+ p_search.add_argument("--limit", type=int, default=20, help="Max results (default: 20)")
66
+ p_search.add_argument("--json", action="store_true", help="Emit JSON")
67
+
68
+ p_show = xref_sub.add_parser("show", help="Show a doc by XID (for on-demand context loading)")
69
+ add_common_config(p_show)
70
+ p_show.add_argument("xid", help="XID to show")
71
+ p_show.add_argument("--max-bytes", type=int, default=20000, help="Truncate output (default: 20000)")
72
+ p_show.add_argument("--json", action="store_true", help="Emit JSON")
73
+
74
+ p_deprecate = xref_sub.add_parser(
75
+ "deprecate",
76
+ help="Mark an old XID doc as deprecated and link to its successor (best-effort)",
77
+ )
78
+ add_common_config(p_deprecate)
79
+ p_deprecate.add_argument("old_xid", help="Deprecated XID (keep the page, add successor link)")
80
+ p_deprecate.add_argument("new_xid", help="Successor XID (add predecessor link)")
81
+ p_deprecate.add_argument("--note", default=None, help="Optional note to include (human-facing)")
82
+
83
+ ctx = subparsers.add_parser("ctx", help="Build compact context packs")
84
+ ctx_sub = ctx.add_subparsers(dest="ctx_cmd", required=True)
85
+
86
+ p_pack = ctx_sub.add_parser("pack", help="Create a compact context pack from seed XIDs")
87
+ add_common_config(p_pack)
88
+ p_pack.add_argument("--seed", action="append", default=[], help="Seed XID (repeatable)")
89
+ p_pack.add_argument("--depth", type=int, default=1, help="Link traversal depth (default: 1)")
90
+ p_pack.add_argument("--max-bytes", type=int, default=40000, help="Max output size (default: 40000)")
91
+ p_pack.add_argument("--per-doc-bytes", type=int, default=8000, help="Max bytes per doc extract (default: 8000)")
92
+ p_pack.add_argument("--out", default=None, help="Write to file instead of stdout")
93
+ p_pack.add_argument("--json", action="store_true", help="Emit JSON (and still write --out if set)")
94
+
95
+ goal = subparsers.add_parser(
96
+ "goal",
97
+ help="Manage goal-mode continuation packets, wake state, and leases after semantic routing selected the goal_mode Skill",
98
+ )
99
+ goal_sub = goal.add_subparsers(dest="goal_cmd", required=True)
100
+
101
+ p_goal_define = goal_sub.add_parser("define", help="Define desired state and acceptance conditions")
102
+ p_goal_define.add_argument("--root", default=".", help="Project root (default: .)")
103
+ p_goal_define.add_argument("--goal", required=True, help="Stable goal id")
104
+ p_goal_define.add_argument("--state", required=True, help="Desired realized state")
105
+ p_goal_define.add_argument(
106
+ "--acceptance", action="append", default=[], required=True,
107
+ help="Acceptance condition as id:text; repeatable",
108
+ )
109
+ p_goal_define.add_argument("--owner", default=None, help="Goal acceptance owner")
110
+ p_goal_define.add_argument("--json", action="store_true", help="Emit JSON")
111
+
112
+ p_goal_show = goal_sub.add_parser("show", help="Show desired, observed, and acceptance state")
113
+ p_goal_show.add_argument("--root", default=".", help="Project root (default: .)")
114
+ p_goal_show.add_argument("--goal", required=True, help="Stable goal id")
115
+ p_goal_show.add_argument("--json", action="store_true", help="Emit JSON")
116
+
117
+ p_goal_complete = goal_sub.add_parser("complete", help="Complete only with acceptance evidence")
118
+ p_goal_complete.add_argument("--root", default=".", help="Project root (default: .)")
119
+ p_goal_complete.add_argument("--goal", required=True, help="Stable goal id")
120
+ p_goal_complete.add_argument(
121
+ "--evidence", action="append", default=[],
122
+ help="Acceptance evidence as condition_id=reference; repeatable",
123
+ )
124
+ p_goal_complete.add_argument("--observed-state", required=True, help="Observed realized state")
125
+ p_goal_complete.add_argument("--json", action="store_true", help="Emit JSON")
126
+
127
+ p_goal_packet = goal_sub.add_parser("packet", help="Manage append-only continuation packets")
128
+ p_goal_packet_sub = p_goal_packet.add_subparsers(dest="packet_cmd", required=True)
129
+
130
+ p_goal_packet_append = p_goal_packet_sub.add_parser("append", help="Append one continuation packet")
131
+ p_goal_packet_append.add_argument("--root", default=".", help="Project root (default: .)")
132
+ p_goal_packet_append.add_argument("--goal", required=True, help="Stable goal id")
133
+ p_goal_packet_append.add_argument("--summary", required=True, help="Goal state summary")
134
+ p_goal_packet_append.add_argument("--next-action", required=True, help="Exact next first action after resume")
135
+ p_goal_packet_append.add_argument("--created-by", default=None, help="Optional packet author label")
136
+ p_goal_packet_append.add_argument("--continuation-log", default=None, help="Continuation log path or reference")
137
+ p_goal_packet_append.add_argument("--artifact", action="append", default=[], help="Artifact path or reference; repeatable")
138
+ p_goal_packet_append.add_argument("--boundary", default=None, help="Current allowed continuation boundary")
139
+ p_goal_packet_append.add_argument("--stop-condition", action="append", default=[], help="Stop condition; repeatable")
140
+ p_goal_packet_append.add_argument("--drift-check", action="append", default=[], help="Drift-check point; repeatable")
141
+ p_goal_packet_append.add_argument(
142
+ "--status",
143
+ choices=sorted({"valid", "superseded", "blocked", "cancelled"}),
144
+ default="valid",
145
+ help="Packet status (default: valid)",
146
+ )
147
+ p_goal_packet_append.add_argument("--source-run-key", default=None, help="Optional source run key")
148
+ p_goal_packet_append.add_argument("--trace-id", default=None, help="Optional trace id")
149
+ p_goal_packet_append.add_argument("--parent-packet", default=None, help="Optional parent packet id")
150
+ p_goal_packet_append.add_argument("--subgoal", default=None, help="Optional subgoal id")
151
+ p_goal_packet_append.add_argument("--resume-blocker", action="append", default=[], help="Resume blocker; repeatable")
152
+ p_goal_packet_append.add_argument("--expiry-hint", default=None, help="Optional expiry hint")
153
+ p_goal_packet_append.add_argument("--json", action="store_true", help="Emit JSON")
154
+
155
+ p_goal_packet_latest = p_goal_packet_sub.add_parser("latest", help="Show the latest continuation packet")
156
+ p_goal_packet_latest.add_argument("--root", default=".", help="Project root (default: .)")
157
+ p_goal_packet_latest.add_argument("--goal", required=True, help="Stable goal id")
158
+ p_goal_packet_latest.add_argument("--valid-only", action="store_true", help="Return only the latest valid packet")
159
+ p_goal_packet_latest.add_argument("--json", action="store_true", help="Emit JSON")
160
+
161
+ p_goal_lease = goal_sub.add_parser("lease", help="Manage goal leases")
162
+ p_goal_lease_sub = p_goal_lease.add_subparsers(dest="lease_cmd", required=True)
163
+
164
+ p_goal_lease_acquire = p_goal_lease_sub.add_parser("acquire", help="Acquire the active lease for one goal")
165
+ p_goal_lease_acquire.add_argument("--root", default=".", help="Project root (default: .)")
166
+ p_goal_lease_acquire.add_argument("--goal", required=True, help="Stable goal id")
167
+ p_goal_lease_acquire.add_argument("--owner", required=True, help="Lease owner id")
168
+ p_goal_lease_acquire.add_argument("--source-packet", default=None, help="Optional packet id; defaults to latest valid packet")
169
+ p_goal_lease_acquire.add_argument("--ttl-hours", type=int, default=6, help="Lease duration in hours (default: 6)")
170
+ p_goal_lease_acquire.add_argument("--json", action="store_true", help="Emit JSON")
171
+
172
+ p_goal_lease_release = p_goal_lease_sub.add_parser("release", help="Release the active lease for one goal")
173
+ p_goal_lease_release.add_argument("--root", default=".", help="Project root (default: .)")
174
+ p_goal_lease_release.add_argument("--goal", required=True, help="Stable goal id")
175
+ p_goal_lease_release.add_argument("--owner", default=None, help="Lease owner id")
176
+ p_goal_lease_release.add_argument("--force", action="store_true", help="Force release even if owner does not match")
177
+ p_goal_lease_release.add_argument("--note", default=None, help="Optional release note")
178
+ p_goal_lease_release.add_argument("--json", action="store_true", help="Emit JSON")
179
+
180
+ p_goal_lease_show = p_goal_lease_sub.add_parser("show", help="Show the current lease state for one goal")
181
+ p_goal_lease_show.add_argument("--root", default=".", help="Project root (default: .)")
182
+ p_goal_lease_show.add_argument("--goal", required=True, help="Stable goal id")
183
+ p_goal_lease_show.add_argument("--json", action="store_true", help="Emit JSON")
184
+
185
+ p_goal_wake = goal_sub.add_parser("wake", help="Manage goal wake observation state")
186
+ p_goal_wake_sub = p_goal_wake.add_subparsers(dest="wake_cmd", required=True)
187
+
188
+ p_goal_wake_observe = p_goal_wake_sub.add_parser("observe", help="Record one wakeup observation for a goal")
189
+ p_goal_wake_observe.add_argument("--root", default=".", help="Project root (default: .)")
190
+ p_goal_wake_observe.add_argument("--goal", required=True, help="Stable goal id")
191
+ p_goal_wake_observe.add_argument("--source", required=True, help="Observer id such as provider poller or dashboard")
192
+ p_goal_wake_observe.add_argument(
193
+ "--recovery-type",
194
+ required=True,
195
+ choices=sorted({"five_hour", "weekly", "unknown"}),
196
+ help="Observed recovery type",
197
+ )
198
+ p_goal_wake_observe.add_argument("--note", default=None, help="Optional observation note")
199
+ p_goal_wake_observe.add_argument("--json", action="store_true", help="Emit JSON")
200
+
201
+ p_goal_wake_show = p_goal_wake_sub.add_parser("show", help="Show the current wake state for one goal")
202
+ p_goal_wake_show.add_argument("--root", default=".", help="Project root (default: .)")
203
+ p_goal_wake_show.add_argument("--goal", required=True, help="Stable goal id")
204
+ p_goal_wake_show.add_argument("--json", action="store_true", help="Emit JSON")
205
+
206
+ gate = subparsers.add_parser(
207
+ "gate",
208
+ help="Agent diff review gate: deterministic, machine-only diff-content checks before CI",
209
+ )
210
+ gate_sub = gate.add_subparsers(dest="gate_cmd", required=True)
211
+
212
+ p_gate_eval = gate_sub.add_parser(
213
+ "eval",
214
+ help="Run deterministic small evals over a diff and emit a pre-CI eval verdict",
215
+ )
216
+ p_gate_eval.add_argument("--root", default=".", help="Project root (default: .)")
217
+ p_gate_eval.add_argument(
218
+ "--diff",
219
+ default=None,
220
+ help="Unified diff file to inspect, or - for stdin; omit to use git diff",
221
+ )
222
+ p_gate_eval.add_argument("--base", default=None, help="git diff base ref (e.g. main); used when --diff is omitted")
223
+ p_gate_eval.add_argument("--staged", action="store_true", help="Inspect staged changes (git diff --cached)")
224
+ p_gate_eval.add_argument(
225
+ "--scope",
226
+ nargs="*",
227
+ default=None,
228
+ help="Declared change-scope globs; files outside are flagged out_of_scope",
229
+ )
230
+ p_gate_eval.add_argument("--json", action="store_true", help="Emit machine-readable JSON")
231
+ p_gate_eval.add_argument(
232
+ "--profile",
233
+ default=None,
234
+ choices=["command-cutover-readiness"],
235
+ help="Run a named repository readiness profile instead of diff checks",
236
+ )
237
+
238
+ pack = subparsers.add_parser("pack", help="Validate Business Pack manifests (pack.md)")
239
+ pack_sub = pack.add_subparsers(dest="pack_cmd", required=True)
240
+
241
+ p_pack_lint = pack_sub.add_parser(
242
+ "lint",
243
+ help="Validate pack manifests: ownership, OS-core contract version, asset resolution, boundary",
244
+ )
245
+ p_pack_lint.add_argument("--root", default=".", help="Project root (default: .)")
246
+ p_pack_lint.add_argument(
247
+ "--manifest",
248
+ default=None,
249
+ help="Relative path to a single pack.md to validate (default: all skills/packs/*/pack.md and packs/*/pack.md)",
250
+ )
251
+ p_pack_lint.add_argument("--json", action="store_true", help="Emit JSON")
252
+
253
+ p_pack_list = pack_sub.add_parser(
254
+ "list",
255
+ help="List Business Packs (pack_id, summary, owned skills) derived from manifests for job-first routing",
256
+ )
257
+ p_pack_list.add_argument("--root", default=".", help="Project root (default: .)")
258
+ p_pack_list.add_argument("--json", action="store_true", help="Emit JSON")
259
+
260
+ dashboard = subparsers.add_parser(
261
+ "dashboard",
262
+ help="Observe Skill run logs through a local Python dashboard",
263
+ )
264
+ dashboard_sub = dashboard.add_subparsers(dest="dashboard_cmd", required=True)
265
+
266
+ p_dashboard_serve = dashboard_sub.add_parser("serve", help="Serve the Skill Run Observation Dashboard")
267
+ p_dashboard_serve.add_argument("--root", default=".", help="Project root (default: .)")
268
+ p_dashboard_serve.add_argument(
269
+ "--sessions-dir",
270
+ default=None,
271
+ help="Session log directory; defaults to <root>/work/sessions",
272
+ )
273
+ p_dashboard_serve.add_argument(
274
+ "--mcp-audit-log",
275
+ default=None,
276
+ help="MCP audit JSONL; defaults to <root>/work/mcp/xid_audit.jsonl",
277
+ )
278
+ p_dashboard_serve.add_argument("--host", default="127.0.0.1", help="Bind host (default: 127.0.0.1)")
279
+ p_dashboard_serve.add_argument("--port", type=int, default=8765, help="Bind port (default: 8765)")
280
+ p_dashboard_serve.add_argument("--open-browser", action="store_true", help="Open the dashboard in a browser")
281
+
282
+ p_dashboard_data = dashboard_sub.add_parser("data", help="Emit dashboard data as JSON")
283
+ p_dashboard_data.add_argument("--root", default=".", help="Project root (default: .)")
284
+ p_dashboard_data.add_argument(
285
+ "--sessions-dir",
286
+ default=None,
287
+ help="Session log directory; defaults to <root>/work/sessions",
288
+ )
289
+ p_dashboard_data.add_argument(
290
+ "--mcp-audit-log",
291
+ default=None,
292
+ help="MCP audit JSONL; defaults to <root>/work/mcp/xid_audit.jsonl",
293
+ )
294
+
295
+ skill = subparsers.add_parser("skill", help="Validate skill metadata before loading")
296
+ skill_sub = skill.add_subparsers(dest="skill_cmd", required=True)
297
+
298
+ p_skill_import = skill_sub.add_parser(
299
+ "import",
300
+ help="Import an external file-based Skill into XRefKit Skill + Knowledge files",
301
+ )
302
+ p_skill_import.add_argument("source_dir", help="External Skill directory or batch root")
303
+ p_skill_import.add_argument("--root", default=".", help="Project root (default: .)")
304
+ p_skill_import.add_argument("--skill-id", help="Target XRefKit skill id")
305
+ p_skill_import.add_argument("--batch", action="store_true", help="Treat source_dir as a root containing skills/ and knowledge/")
306
+ p_skill_import.add_argument("--skill-id-prefix", default=None, help="Prefix for generated skill ids in --batch mode")
307
+ p_skill_import.add_argument("--source-skill-doc", default=None, help="Source skill document path relative to source_dir")
308
+ p_skill_import.add_argument("--target-skill-dir", default=None, help="Target Skill directory")
309
+ p_skill_import.add_argument("--target-skill-root", default=None, help="Batch target Skill root")
310
+ p_skill_import.add_argument("--target-knowledge-dir", default=None, help="Target Knowledge directory")
311
+ p_skill_import.add_argument("--dry-run", action="store_true", help="Show planned output without writing files")
312
+ p_skill_import.add_argument("--json", action="store_true", help="Emit JSON")
313
+
314
+ p_skill_check = skill_sub.add_parser("check", help="Validate skill meta guard compliance")
315
+ p_skill_check.add_argument("--root", default=".", help="Project root (default: .)")
316
+ p_skill_check.add_argument("--meta", default=None, help="Relative path to a single meta.md to validate")
317
+ p_skill_check.add_argument(
318
+ "--scope",
319
+ choices=["skills", "all"],
320
+ default="skills",
321
+ help="Validation scope when --meta is omitted (default: skills)",
322
+ )
323
+ p_skill_check.add_argument(
324
+ "--level",
325
+ choices=["auto", "draft", "trial", "stable", "governed"],
326
+ default="auto",
327
+ help="Validation level; auto uses declared maturity/status (default: auto)",
328
+ )
329
+ p_skill_check.add_argument("--json", action="store_true", help="Emit JSON")
330
+
331
+ p_skill_list = skill_sub.add_parser(
332
+ "list",
333
+ help="List skills with publication boundary (public/private) and detect private-leak violations",
334
+ )
335
+ p_skill_list.add_argument("--root", default=".", help="Project root (default: .)")
336
+ p_skill_list.add_argument("--json", action="store_true", help="Emit JSON")
337
+
338
+ p_skill_index = skill_sub.add_parser(
339
+ "index",
340
+ help="Generate skills/_index.md from catalog-visible skill metadata",
341
+ )
342
+ p_skill_index.add_argument("--root", default=".", help="Project root (default: .)")
343
+ p_skill_index.add_argument("--write", action="store_true", help="Write skills/_index.md instead of printing")
344
+ p_skill_index.add_argument("--json", action="store_true", help="Emit JSON")
345
+
346
+ p_skill_merge_plan = skill_sub.add_parser(
347
+ "merge-plan",
348
+ help="Create a deterministic report for importing an older Skill asset",
349
+ )
350
+ p_skill_merge_plan.add_argument("--root", default=".", help="Project root (default: .)")
351
+ p_skill_merge_plan.add_argument("--source", required=True, help="Source Skill folder or import bundle")
352
+ p_skill_merge_plan.add_argument("--target-skill", default=None, help="Optional intended current target skill_id")
353
+ p_skill_merge_plan.add_argument("--source-version", default=None, help="Optional source version label")
354
+ p_skill_merge_plan.add_argument("--json", action="store_true", help="Emit JSON")
355
+
356
+ p_skill_run = skill_sub.add_parser("run", help="Create a Skill runtime envelope and session log")
357
+ p_skill_run.add_argument("--root", default=".", help="Project root (default: .)")
358
+ p_skill_run.add_argument("--meta", required=True, help="Relative path to the Skill meta.md to run")
359
+ p_skill_run.add_argument("--task", default=None, help="Task text for the Skill run")
360
+ p_skill_run.add_argument("--task-file", default=None, help="Read task text from a UTF-8 file")
361
+ p_skill_run.add_argument("--out", default=None, help="Write run log to this path")
362
+ p_skill_run.add_argument("--run-id", default=None, help="Caller-supplied UUID used to correlate MCP and client logs")
363
+ p_skill_run.add_argument(
364
+ "--domain-knowledge-catalog",
365
+ default=None,
366
+ help="JSON fixture/catalog of available domain knowledge metadata for this run",
367
+ )
368
+ p_skill_run.add_argument(
369
+ "--knowledge-input",
370
+ action="append",
371
+ default=[],
372
+ help="Selected domain knowledge input as name=XID[,XID]; may be repeated",
373
+ )
374
+ p_skill_run.add_argument(
375
+ "--handoff-source-log",
376
+ action="append",
377
+ default=[],
378
+ help="Prior Skill run log that handed work into this startup; may be repeated",
379
+ )
380
+ p_skill_run.add_argument("--json", action="store_true", help="Emit JSON")
381
+
382
+ p_skill_correlate = skill_sub.add_parser("correlate", help="Bind a Skill run log to its MCP session")
383
+ p_skill_correlate.add_argument("--log", required=True, help="Skill run log to update")
384
+ p_skill_correlate.add_argument("--run-id", default=None, help="Expected run_id returned by bind_skill_run")
385
+ p_skill_correlate.add_argument("--mcp-session-id", required=True, help="MCP session ID returned by bind_skill_run")
386
+ p_skill_correlate.add_argument(
387
+ "--repository-fingerprint",
388
+ required=True,
389
+ help="Repository fingerprint returned by bind_skill_run",
390
+ )
391
+ p_skill_correlate.add_argument("--json", action="store_true", help="Emit JSON")
392
+
393
+ p_skill_routing = skill_sub.add_parser("routing", help="Record Skill routing candidates and selection evidence")
394
+ p_skill_routing.add_argument("--log", required=True, help="Skill run log to update")
395
+ p_skill_routing.add_argument("--selected-skill", required=True, help="Selected Skill ID")
396
+ p_skill_routing.add_argument("--candidate", action="append", default=[], help="Candidate Skill ID; repeatable")
397
+ p_skill_routing.add_argument(
398
+ "--selection-mode",
399
+ choices=["semantic", "explicit", "handoff", "fallback"],
400
+ default="semantic",
401
+ help="Routing decision mode",
402
+ )
403
+ p_skill_routing.add_argument("--reason", required=True, help="Evidence-bound selection reason")
404
+ p_skill_routing.add_argument("--json", action="store_true", help="Emit JSON")
405
+
406
+ p_skill_knowledge = skill_sub.add_parser("knowledge", help="Record Knowledge search, load, or application evidence")
407
+ p_skill_knowledge.add_argument("--log", required=True, help="Skill run log to update")
408
+ p_skill_knowledge.add_argument("--action", required=True, choices=["search", "load", "apply"])
409
+ p_skill_knowledge.add_argument("--query", default=None, help="Search query for action=search")
410
+ p_skill_knowledge.add_argument("--xid", action="append", default=[], help="Knowledge XID; repeatable for search results")
411
+ p_skill_knowledge.add_argument("--content-hash", default=None, help="Document content hash for action=load or action=apply")
412
+ p_skill_knowledge.add_argument(
413
+ "--status",
414
+ choices=["hit", "miss", "fallback"],
415
+ default="hit",
416
+ help="Search result for action=search",
417
+ )
418
+ p_skill_knowledge.add_argument("--source", default="client", help="Observation source such as mcp or filesystem")
419
+ p_skill_knowledge.add_argument("--target", default=None, help="Judgment or artifact target for action=apply")
420
+ p_skill_knowledge.add_argument("--decisive", action="store_true", help="Mark the XID as decision-changing evidence")
421
+ p_skill_knowledge.add_argument("--note", default=None, help="Optional observation note")
422
+ p_skill_knowledge.add_argument("--json", action="store_true", help="Emit JSON")
423
+
424
+ p_skill_feedback = skill_sub.add_parser("feedback", help="Record human or downstream outcome feedback")
425
+ p_skill_feedback.add_argument("--log", required=True, help="Skill run log to update")
426
+ p_skill_feedback.add_argument("--kind", required=True, choices=["human", "outcome"])
427
+ p_skill_feedback.add_argument(
428
+ "--status",
429
+ required=True,
430
+ choices=["accepted", "corrected", "rejected", "successful", "failed", "mixed", "unknown"],
431
+ )
432
+ p_skill_feedback.add_argument("--target", default=None, help="Feedback target artifact, judgment, or deployment")
433
+ p_skill_feedback.add_argument("--note", required=True, help="Observed feedback or outcome")
434
+ p_skill_feedback.add_argument("--json", action="store_true", help="Emit JSON")
435
+
436
+ p_skill_phase = skill_sub.add_parser("phase", help="Update a Skill run log phase state")
437
+ p_skill_phase.add_argument("--log", required=True, help="Skill run log to update")
438
+ p_skill_phase.add_argument(
439
+ "--phase",
440
+ required=True,
441
+ choices=["startup", "planning", "execution", "check", "quality", "closure", "handoff"],
442
+ help="Phase to update",
443
+ )
444
+ p_skill_phase.add_argument(
445
+ "--status",
446
+ required=True,
447
+ choices=["pending", "in_progress", "done", "blocked", "unknown", "escalated"],
448
+ help="Phase status",
449
+ )
450
+ p_skill_phase.add_argument("--note", default=None, help="Optional phase event note")
451
+ p_skill_phase.add_argument(
452
+ "--role",
453
+ default=None,
454
+ help="Runtime role assigned by xrefkit skill run; required for execution, check, and handoff phases",
455
+ )
456
+ p_skill_phase.add_argument("--json", action="store_true", help="Emit JSON")
457
+
458
+ p_skill_workitem = skill_sub.add_parser("workitem", help="Add or update a concrete Skill work item")
459
+ p_skill_workitem.add_argument("--log", required=True, help="Skill run log to update")
460
+ p_skill_workitem.add_argument("--item", required=True, help="Stable work item id, such as WI-001")
461
+ p_skill_workitem.add_argument("--text", default=None, help="Work item text; required when adding a new item")
462
+ p_skill_workitem.add_argument(
463
+ "--status",
464
+ required=True,
465
+ choices=["pending", "in_progress", "done", "blocked", "unknown", "escalated"],
466
+ help="Work item status",
467
+ )
468
+ p_skill_workitem.add_argument("--role", required=True, help="Runtime role updating the work item")
469
+ p_skill_workitem.add_argument("--json", action="store_true", help="Emit JSON")
470
+
471
+ p_skill_artifact = skill_sub.add_parser("artifact", help="Add or update a Skill runtime artifact/evidence link")
472
+ p_skill_artifact.add_argument("--log", required=True, help="Skill run log to update")
473
+ p_skill_artifact.add_argument("--artifact", required=True, help="Stable artifact id, such as OUT-001")
474
+ p_skill_artifact.add_argument(
475
+ "--kind",
476
+ required=True,
477
+ choices=["output", "evidence", "check", "judgment", "source", "handoff"],
478
+ help="Artifact kind",
479
+ )
480
+ p_skill_artifact.add_argument(
481
+ "--status",
482
+ required=True,
483
+ choices=["pending", "in_progress", "done", "blocked", "unknown", "escalated"],
484
+ help="Artifact status",
485
+ )
486
+ p_skill_artifact.add_argument("--target", default=None, help="Path, XID, command, URL, or other trace target")
487
+ p_skill_artifact.add_argument("--item", default=None, help="Optional related concrete work item id")
488
+ p_skill_artifact.add_argument("--role", required=True, help="Runtime role updating the artifact")
489
+ p_skill_artifact.add_argument("--note", default=None, help="Optional artifact note")
490
+ p_skill_artifact.add_argument("--json", action="store_true", help="Emit JSON")
491
+
492
+ p_skill_concern = skill_sub.add_parser("concern", help="Add or update unknown, risk, or judgment closure linkage")
493
+ p_skill_concern.add_argument("--log", required=True, help="Skill run log to update")
494
+ p_skill_concern.add_argument("--concern", required=True, help="Stable concern id, such as UNK-001")
495
+ p_skill_concern.add_argument(
496
+ "--kind",
497
+ required=True,
498
+ choices=["unknown", "risk", "judgment"],
499
+ help="Concern kind",
500
+ )
501
+ p_skill_concern.add_argument(
502
+ "--status",
503
+ required=True,
504
+ choices=["open", "resolved", "escalated"],
505
+ help="Concern status",
506
+ )
507
+ p_skill_concern.add_argument(
508
+ "--judgment",
509
+ default="trivial",
510
+ choices=["trivial", "non_trivial"],
511
+ help="Judgment significance; only non_trivial judgments require artifact/reference linkage",
512
+ )
513
+ p_skill_concern.add_argument("--target", default=None, help="Optional path, XID, command, URL, or judgment reference")
514
+ p_skill_concern.add_argument("--text", default=None, help="Concern text; required when adding a new concern")
515
+ p_skill_concern.add_argument("--role", required=True, help="Runtime role recording the concern")
516
+ p_skill_concern.add_argument("--json", action="store_true", help="Emit JSON")
517
+
518
+ p_skill_tokens = skill_sub.add_parser("tokens", help="Record token usage consumed by a Skill run")
519
+ p_skill_tokens.add_argument("--log", required=True, help="Skill run log to update")
520
+ p_skill_tokens.add_argument("--input", type=int, default=None, help="Input (prompt) tokens consumed")
521
+ p_skill_tokens.add_argument("--output", type=int, default=None, help="Output (completion) tokens consumed")
522
+ p_skill_tokens.add_argument("--total", type=int, default=None, help="Total tokens; defaults to input + output")
523
+ p_skill_tokens.add_argument("--note", default=None, help="Optional token usage note")
524
+ p_skill_tokens.add_argument("--json", action="store_true", help="Emit JSON")
525
+
526
+ p_skill_close = skill_sub.add_parser("close", help="Apply the Skill run closure gate")
527
+ p_skill_close.add_argument("--log", required=True, help="Skill run log to close")
528
+ p_skill_close.add_argument("--note", default=None, help="Optional closure event note")
529
+ p_skill_close.add_argument("--json", action="store_true", help="Emit JSON")
530
+
531
+ p_skill_verify = skill_sub.add_parser(
532
+ "verify",
533
+ help="Deterministically verify workflow progression and advance the check phase",
534
+ )
535
+ p_skill_verify.add_argument("--log", required=True, help="Skill run log to verify")
536
+ p_skill_verify.add_argument("--note", default=None, help="Optional check event note")
537
+ p_skill_verify.add_argument("--json", action="store_true", help="Emit JSON")
538
+
539
+ return parser
540
+
541
+
542
+ def main(argv: list[str] | None = None) -> int:
543
+ try:
544
+ sys.stdout.reconfigure(encoding="utf-8")
545
+ sys.stderr.reconfigure(encoding="utf-8")
546
+ except Exception:
547
+ pass
548
+
549
+ parser = _build_parser()
550
+ args = parser.parse_args(argv)
551
+
552
+ if args.command == "xref":
553
+ cfg = XrefConfig(
554
+ root=args.root,
555
+ include=args.include,
556
+ exclude=args.exclude,
557
+ )
558
+ return cmd_xref(args, cfg)
559
+
560
+ if args.command == "ctx":
561
+ from xrefkit.ctx import cmd_ctx
562
+
563
+ cfg = XrefConfig(
564
+ root=args.root,
565
+ include=args.include,
566
+ exclude=args.exclude,
567
+ )
568
+ return cmd_ctx(args, cfg)
569
+
570
+ if args.command == "skill":
571
+ if args.skill_cmd == "import":
572
+ from xrefkit.import_skill import cmd_skill_import
573
+
574
+ return cmd_skill_import(args)
575
+ if args.skill_cmd == "list":
576
+ from xrefkit.skillmeta import cmd_skill_list
577
+
578
+ return cmd_skill_list(args)
579
+ if args.skill_cmd == "index":
580
+ from xrefkit.skillmeta import cmd_skill_index
581
+
582
+ return cmd_skill_index(args)
583
+ if args.skill_cmd == "merge-plan":
584
+ from xrefkit.skillmeta import cmd_skill_merge_plan
585
+
586
+ return cmd_skill_merge_plan(args)
587
+ if args.skill_cmd == "run":
588
+ from xrefkit.skillrun import cmd_skill_run
589
+
590
+ return cmd_skill_run(args)
591
+ if args.skill_cmd == "correlate":
592
+ from xrefkit.skillrun import cmd_skill_correlate
593
+
594
+ return cmd_skill_correlate(args)
595
+ if args.skill_cmd == "routing":
596
+ from xrefkit.skillrun import cmd_skill_routing
597
+
598
+ return cmd_skill_routing(args)
599
+ if args.skill_cmd == "knowledge":
600
+ from xrefkit.skillrun import cmd_skill_knowledge
601
+
602
+ return cmd_skill_knowledge(args)
603
+ if args.skill_cmd == "feedback":
604
+ from xrefkit.skillrun import cmd_skill_feedback
605
+
606
+ return cmd_skill_feedback(args)
607
+ if args.skill_cmd == "phase":
608
+ from xrefkit.skillrun import cmd_skill_phase
609
+
610
+ return cmd_skill_phase(args)
611
+ if args.skill_cmd == "workitem":
612
+ from xrefkit.skillrun import cmd_skill_workitem
613
+
614
+ return cmd_skill_workitem(args)
615
+ if args.skill_cmd == "artifact":
616
+ from xrefkit.skillrun import cmd_skill_artifact
617
+
618
+ return cmd_skill_artifact(args)
619
+ if args.skill_cmd == "concern":
620
+ from xrefkit.skillrun import cmd_skill_concern
621
+
622
+ return cmd_skill_concern(args)
623
+ if args.skill_cmd == "tokens":
624
+ from xrefkit.skillrun import cmd_skill_tokens
625
+
626
+ return cmd_skill_tokens(args)
627
+ if args.skill_cmd == "close":
628
+ from xrefkit.skillrun import cmd_skill_close
629
+
630
+ return cmd_skill_close(args)
631
+ if args.skill_cmd == "verify":
632
+ from xrefkit.skillrun import cmd_skill_verify
633
+
634
+ return cmd_skill_verify(args)
635
+
636
+ from xrefkit.skillmeta import cmd_skill
637
+
638
+ return cmd_skill(args)
639
+
640
+ if args.command == "pack":
641
+ if args.pack_cmd == "list":
642
+ from xrefkit.packmeta import cmd_pack_list
643
+
644
+ return cmd_pack_list(args)
645
+
646
+ from xrefkit.packmeta import cmd_pack_lint
647
+
648
+ return cmd_pack_lint(args)
649
+
650
+ if args.command == "dashboard":
651
+ from xrefkit.dashboard import cmd_dashboard
652
+
653
+ return cmd_dashboard(args)
654
+
655
+ if args.command == "gate":
656
+ from xrefkit.gate import cmd_gate
657
+
658
+ return cmd_gate(args)
659
+
660
+ if args.command == "goal":
661
+ from xrefkit.goalstate import cmd_goal
662
+
663
+ return cmd_goal(args)
664
+
665
+ parser.print_help()
666
+ return 2
667
+
668
+
669
+ if __name__ == "__main__":
670
+ raise SystemExit(main(sys.argv[1:]))