xrefkit 0.4.8__tar.gz → 0.4.10__tar.gz
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.
- xrefkit-0.4.10/PKG-INFO +121 -0
- xrefkit-0.4.10/README.md +82 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/pyproject.toml +1 -1
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_cli.py +57 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_dashboard.py +153 -0
- xrefkit-0.4.10/tests/test_host_precheck.py +49 -0
- xrefkit-0.4.10/tests/test_instruction_workflow.py +462 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/__init__.py +1 -1
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/cli.py +7 -2
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/dashboard.py +425 -7
- xrefkit-0.4.10/xrefkit/host_precheck.py +125 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/import_skill.py +55 -22
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/mcp/__init__.py +10 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/mcp/audit.py +45 -3
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/mcp/catalog.py +56 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/mcp/client_cache.py +21 -0
- xrefkit-0.4.10/xrefkit/mcp/client_flow.py +325 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/mcp/context_token.py +22 -1
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/mcp/contracts.py +10 -2
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/mcp/schemas.py +2 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/mcp/server.py +44 -1
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/mcp/startup_contract_pack.py +8 -4
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/operations_cli.py +176 -3
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/skillrun.py +597 -16
- xrefkit-0.4.10/xrefkit.egg-info/PKG-INFO +121 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit.egg-info/SOURCES.txt +3 -0
- xrefkit-0.4.8/PKG-INFO +0 -372
- xrefkit-0.4.8/README.md +0 -333
- xrefkit-0.4.8/tests/test_instruction_workflow.py +0 -172
- xrefkit-0.4.8/xrefkit.egg-info/PKG-INFO +0 -372
- {xrefkit-0.4.8 → xrefkit-0.4.10}/LICENSE +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/setup.cfg +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_base_sync_ownership.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_boundary_analysis.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_brownfield_file_editing_protocol.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_calibration_lint.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_check_skill_knowledge_xids.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_collect_analyzer_sarif.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_convert_to_xrefkit_skill.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_cs_scope_probe.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_csharp_commonality.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_csharp_naming_profile.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_ctx.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_cutover_readiness.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_error_policy_audit.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_error_policy_locator.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_fm_multiroot.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_gate.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_goal_desired_state.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_human_evaluation.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_knowledge_relations_validator.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_mcp_setup.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_ownership.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_packmeta.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_project_quality_baseline.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_resource_provider.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_runtime_contracts.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_sarif_to_locator.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_skill_runtime_audit.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_skillmeta.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_skills_sync.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_structure_catalog.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_xref.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_xrefkit_instance.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_xrefkit_tools.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_xrefkit_v2_discovery.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_xrefkit_v2_models.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/tests/test_xrefkit_v2_pipeline.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/__main__.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/boundary_analysis.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/catalog_cli.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/contracts.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/ctx.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/discovery.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/gate.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/goalstate.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/hashing.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/instance.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/loaders.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/mcp/bootstrap.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/mcp/cli.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/mcp/context_registry.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/mcp/dist.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/mcp/ownership.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/mcp/repository.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/mcp/setup.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/mcp_tools.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/models/__init__.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/models/common.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/models/effective_bundle.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/models/human_evaluation.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/models/local_manifest.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/models/package_manifest.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/models/run_log.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/models/server_config.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/models/skill_definition.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/ownership.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/packmeta.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/registry.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/resolver.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/resource_provider.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/resources/base/contracts.json +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/resources/base/current.json +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/resources/base/generations/7a682a5272907354/contracts.json +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/resources/base/generations/7a682a5272907354/model_body.md +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/resources/base/generations/9929294385ccb7b0/contracts.json +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/resources/base/generations/9929294385ccb7b0/model_body.md +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/resources/base/model_body.md +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/runlog.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/skillmeta.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/skills_sync.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/structure_catalog.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/tools/__init__.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/tools/__main__.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/v2_cli.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/workspace.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit/xref.py +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit.egg-info/dependency_links.txt +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit.egg-info/entry_points.txt +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit.egg-info/requires.txt +0 -0
- {xrefkit-0.4.8 → xrefkit-0.4.10}/xrefkit.egg-info/top_level.txt +0 -0
xrefkit-0.4.10/PKG-INFO
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: xrefkit
|
|
3
|
+
Version: 0.4.10
|
|
4
|
+
Summary: Portable XID, Skill, Knowledge, workflow, and MCP runtime for XRefKit
|
|
5
|
+
Author: synthaicode
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Ritu
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Requires-Python: >=3.11
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Requires-Dist: PyYAML<7,>=6.0.2
|
|
32
|
+
Requires-Dist: pydantic<3,>=2.0
|
|
33
|
+
Provides-Extra: mcp
|
|
34
|
+
Requires-Dist: mcp>=1.0.0; extra == "mcp"
|
|
35
|
+
Requires-Dist: uvicorn>=0.30; extra == "mcp"
|
|
36
|
+
Provides-Extra: test
|
|
37
|
+
Requires-Dist: pytest>=8.0.0; extra == "test"
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
|
|
40
|
+
# XRefKit
|
|
41
|
+
|
|
42
|
+
XRefKit is a framework for making AI-assisted work repeatable, reviewable, and
|
|
43
|
+
handoff-ready.
|
|
44
|
+
|
|
45
|
+
It helps teams turn domain procedures and knowledge into work that can be
|
|
46
|
+
performed with explicit evidence, human judgment, and completion checks.
|
|
47
|
+
|
|
48
|
+
## Why XRefKit?
|
|
49
|
+
|
|
50
|
+
Using AI for real work creates recurring operating problems:
|
|
51
|
+
|
|
52
|
+

|
|
53
|
+
|
|
54
|
+
- the AI can act from incomplete context or unsupported guesses
|
|
55
|
+
- procedures, domain facts, and judgment criteria get mixed together in prompts
|
|
56
|
+
- execution, checking, and handoff collapse into one opaque step
|
|
57
|
+
- work becomes hard to continue across agents, humans, or sessions
|
|
58
|
+
- outputs may lack evidence, closure discipline, or auditability
|
|
59
|
+
|
|
60
|
+
XRefKit provides a repository and runtime model for addressing these problems.
|
|
61
|
+
|
|
62
|
+
## What it provides
|
|
63
|
+
|
|
64
|
+
- **Skills** — reusable procedures for a defined kind of work
|
|
65
|
+
- **Knowledge** — source-backed domain facts and local rules
|
|
66
|
+
- **Workflow protocol** — recorded progress, deterministic verification, and
|
|
67
|
+
closure checks
|
|
68
|
+
- **Evidence and handoffs** — outputs, judgments, concerns, and decisions that
|
|
69
|
+
remain reviewable after the work is done
|
|
70
|
+
- **Skill Run Dashboard** — inspect Skill execution status, referenced XIDs,
|
|
71
|
+
evidence, judgments, concerns, and handoffs to improve the auditability of
|
|
72
|
+
results
|
|
73
|
+
- **XIDs** — stable references for connecting procedures, knowledge, and
|
|
74
|
+
supporting documents
|
|
75
|
+
|
|
76
|
+
The package includes the resolver, Skill runtime, workflow controls, client
|
|
77
|
+
tools, and an optional MCP adapter.
|
|
78
|
+
|
|
79
|
+
The [Skill Run Dashboard](docs/guides/086_skill_run_observation_dashboard_usage.md#xid-4A4763A2DE63)
|
|
80
|
+
helps people trace how a Skill run used its referenced XIDs and recorded its
|
|
81
|
+
evidence before accepting or handing off the result.
|
|
82
|
+
|
|
83
|
+
## Quick start
|
|
84
|
+
|
|
85
|
+
XRefKit requires Python 3.11 or later.
|
|
86
|
+
|
|
87
|
+
```powershell
|
|
88
|
+
python -m pip install xrefkit
|
|
89
|
+
xrefkit init
|
|
90
|
+
xrefkit --help
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
For local development:
|
|
94
|
+
|
|
95
|
+
```powershell
|
|
96
|
+
python -m pip install -e .
|
|
97
|
+
xrefkit init
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
For the optional MCP server:
|
|
101
|
+
|
|
102
|
+
```powershell
|
|
103
|
+
python -m pip install "xrefkit[mcp]"
|
|
104
|
+
xrefkit mcp serve --repo . --transport stdio
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Where to go next
|
|
108
|
+
|
|
109
|
+
- [Install XRefKit and register Skill Packages](docs/guides/089_xrefkit_package_first_registration.md#xid-4F8C2A7D1E90)
|
|
110
|
+
- [Understand the workflow protocol](docs/guides/087_workflow_protocol_sequence_for_humans.md#xid-E8B4D2F19A63)
|
|
111
|
+
- [Use an instruction-backed workflow](docs/guides/088_instruction_workflow_protocol.md#xid-9F4C2A7D1B60)
|
|
112
|
+
- [Understand Skills and Knowledge](docs/core/models/052_flow_capability_skill_knowledge_model.md#xid-91C4B7E2D5A8)
|
|
113
|
+
- [Author a Skill with xref](docs/guides/013_skill_authoring_with_xref.md#xid-3DB05A0F5F5B)
|
|
114
|
+
- [Browse the complete documentation index](docs/000_index.md#xid-56DD6EB68343)
|
|
115
|
+
|
|
116
|
+
## Security
|
|
117
|
+
|
|
118
|
+
XRefKit does not require provider API keys to explore or install the package.
|
|
119
|
+
Do not commit secrets, API keys, access tokens, `.env` files, or provider
|
|
120
|
+
credentials. Authenticate external AI tools through their official provider
|
|
121
|
+
mechanisms.
|
xrefkit-0.4.10/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# XRefKit
|
|
2
|
+
|
|
3
|
+
XRefKit is a framework for making AI-assisted work repeatable, reviewable, and
|
|
4
|
+
handoff-ready.
|
|
5
|
+
|
|
6
|
+
It helps teams turn domain procedures and knowledge into work that can be
|
|
7
|
+
performed with explicit evidence, human judgment, and completion checks.
|
|
8
|
+
|
|
9
|
+
## Why XRefKit?
|
|
10
|
+
|
|
11
|
+
Using AI for real work creates recurring operating problems:
|
|
12
|
+
|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
- the AI can act from incomplete context or unsupported guesses
|
|
16
|
+
- procedures, domain facts, and judgment criteria get mixed together in prompts
|
|
17
|
+
- execution, checking, and handoff collapse into one opaque step
|
|
18
|
+
- work becomes hard to continue across agents, humans, or sessions
|
|
19
|
+
- outputs may lack evidence, closure discipline, or auditability
|
|
20
|
+
|
|
21
|
+
XRefKit provides a repository and runtime model for addressing these problems.
|
|
22
|
+
|
|
23
|
+
## What it provides
|
|
24
|
+
|
|
25
|
+
- **Skills** — reusable procedures for a defined kind of work
|
|
26
|
+
- **Knowledge** — source-backed domain facts and local rules
|
|
27
|
+
- **Workflow protocol** — recorded progress, deterministic verification, and
|
|
28
|
+
closure checks
|
|
29
|
+
- **Evidence and handoffs** — outputs, judgments, concerns, and decisions that
|
|
30
|
+
remain reviewable after the work is done
|
|
31
|
+
- **Skill Run Dashboard** — inspect Skill execution status, referenced XIDs,
|
|
32
|
+
evidence, judgments, concerns, and handoffs to improve the auditability of
|
|
33
|
+
results
|
|
34
|
+
- **XIDs** — stable references for connecting procedures, knowledge, and
|
|
35
|
+
supporting documents
|
|
36
|
+
|
|
37
|
+
The package includes the resolver, Skill runtime, workflow controls, client
|
|
38
|
+
tools, and an optional MCP adapter.
|
|
39
|
+
|
|
40
|
+
The [Skill Run Dashboard](docs/guides/086_skill_run_observation_dashboard_usage.md#xid-4A4763A2DE63)
|
|
41
|
+
helps people trace how a Skill run used its referenced XIDs and recorded its
|
|
42
|
+
evidence before accepting or handing off the result.
|
|
43
|
+
|
|
44
|
+
## Quick start
|
|
45
|
+
|
|
46
|
+
XRefKit requires Python 3.11 or later.
|
|
47
|
+
|
|
48
|
+
```powershell
|
|
49
|
+
python -m pip install xrefkit
|
|
50
|
+
xrefkit init
|
|
51
|
+
xrefkit --help
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
For local development:
|
|
55
|
+
|
|
56
|
+
```powershell
|
|
57
|
+
python -m pip install -e .
|
|
58
|
+
xrefkit init
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
For the optional MCP server:
|
|
62
|
+
|
|
63
|
+
```powershell
|
|
64
|
+
python -m pip install "xrefkit[mcp]"
|
|
65
|
+
xrefkit mcp serve --repo . --transport stdio
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Where to go next
|
|
69
|
+
|
|
70
|
+
- [Install XRefKit and register Skill Packages](docs/guides/089_xrefkit_package_first_registration.md#xid-4F8C2A7D1E90)
|
|
71
|
+
- [Understand the workflow protocol](docs/guides/087_workflow_protocol_sequence_for_humans.md#xid-E8B4D2F19A63)
|
|
72
|
+
- [Use an instruction-backed workflow](docs/guides/088_instruction_workflow_protocol.md#xid-9F4C2A7D1B60)
|
|
73
|
+
- [Understand Skills and Knowledge](docs/core/models/052_flow_capability_skill_knowledge_model.md#xid-91C4B7E2D5A8)
|
|
74
|
+
- [Author a Skill with xref](docs/guides/013_skill_authoring_with_xref.md#xid-3DB05A0F5F5B)
|
|
75
|
+
- [Browse the complete documentation index](docs/000_index.md#xid-56DD6EB68343)
|
|
76
|
+
|
|
77
|
+
## Security
|
|
78
|
+
|
|
79
|
+
XRefKit does not require provider API keys to explore or install the package.
|
|
80
|
+
Do not commit secrets, API keys, access tokens, `.env` files, or provider
|
|
81
|
+
credentials. Authenticate external AI tools through their official provider
|
|
82
|
+
mechanisms.
|
|
@@ -1464,6 +1464,63 @@ class CliTests(unittest.TestCase):
|
|
|
1464
1464
|
self.assertIn("## Closure Gate\n\n- status: `done`", text)
|
|
1465
1465
|
self.assertIn("`closure` -> `done` role=`closure_gate`: closure gate accepted completed run", text)
|
|
1466
1466
|
|
|
1467
|
+
def test_skill_import_invalid_batch_input_returns_safe_json_error(self) -> None:
|
|
1468
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
1469
|
+
root = Path(tmp) / "repo"
|
|
1470
|
+
source = Path(tmp) / "not-a-batch"
|
|
1471
|
+
source.mkdir()
|
|
1472
|
+
|
|
1473
|
+
stdout = io.StringIO()
|
|
1474
|
+
stderr = io.StringIO()
|
|
1475
|
+
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
|
|
1476
|
+
exit_code = main(
|
|
1477
|
+
[
|
|
1478
|
+
"skill",
|
|
1479
|
+
"import",
|
|
1480
|
+
str(source),
|
|
1481
|
+
"--root",
|
|
1482
|
+
str(root),
|
|
1483
|
+
"--batch",
|
|
1484
|
+
"--json",
|
|
1485
|
+
]
|
|
1486
|
+
)
|
|
1487
|
+
|
|
1488
|
+
payload = json.loads(stdout.getvalue())
|
|
1489
|
+
self.assertEqual(2, exit_code)
|
|
1490
|
+
self.assertFalse(payload["ok"])
|
|
1491
|
+
self.assertEqual("invalid_input", payload["error"]["code"])
|
|
1492
|
+
self.assertEqual("batch source root must contain a skills/ directory", payload["error"]["message"])
|
|
1493
|
+
self.assertNotIn(str(root), stdout.getvalue())
|
|
1494
|
+
self.assertNotIn(str(source), stdout.getvalue())
|
|
1495
|
+
self.assertEqual("", stderr.getvalue())
|
|
1496
|
+
|
|
1497
|
+
def test_skill_import_missing_document_returns_safe_text_error(self) -> None:
|
|
1498
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
1499
|
+
root = Path(tmp) / "repo"
|
|
1500
|
+
source = Path(tmp) / "empty-skill"
|
|
1501
|
+
source.mkdir()
|
|
1502
|
+
|
|
1503
|
+
stdout = io.StringIO()
|
|
1504
|
+
stderr = io.StringIO()
|
|
1505
|
+
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
|
|
1506
|
+
exit_code = main(
|
|
1507
|
+
[
|
|
1508
|
+
"skill",
|
|
1509
|
+
"import",
|
|
1510
|
+
str(source),
|
|
1511
|
+
"--root",
|
|
1512
|
+
str(root),
|
|
1513
|
+
"--skill-id",
|
|
1514
|
+
"legacy_review",
|
|
1515
|
+
]
|
|
1516
|
+
)
|
|
1517
|
+
|
|
1518
|
+
self.assertEqual(2, exit_code)
|
|
1519
|
+
self.assertEqual("", stdout.getvalue())
|
|
1520
|
+
self.assertIn("could not find SKILL.md or README.md in the source Skill directory", stderr.getvalue())
|
|
1521
|
+
self.assertNotIn(str(root), stderr.getvalue())
|
|
1522
|
+
self.assertNotIn(str(source), stderr.getvalue())
|
|
1523
|
+
|
|
1467
1524
|
|
|
1468
1525
|
if __name__ == "__main__":
|
|
1469
1526
|
unittest.main()
|
|
@@ -241,6 +241,149 @@ class DashboardTests(unittest.TestCase):
|
|
|
241
241
|
self.assertEqual(1, payload["summary"]["runs"])
|
|
242
242
|
self.assertEqual("sample_skill", payload["runs"][0]["skill_id"])
|
|
243
243
|
|
|
244
|
+
def test_dashboard_exposes_recovery_trace(self) -> None:
|
|
245
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
246
|
+
root = Path(tmp)
|
|
247
|
+
run_log = self._write_closed_run(root)
|
|
248
|
+
common = [
|
|
249
|
+
"workflow",
|
|
250
|
+
"recovery",
|
|
251
|
+
"--log",
|
|
252
|
+
str(run_log),
|
|
253
|
+
"--recovery-id",
|
|
254
|
+
"REC-001",
|
|
255
|
+
"--resume-location",
|
|
256
|
+
"after reconcile",
|
|
257
|
+
"--reason",
|
|
258
|
+
"child status was not yet projected",
|
|
259
|
+
"--next-action",
|
|
260
|
+
"confirm and rerun reconcile",
|
|
261
|
+
]
|
|
262
|
+
self._run_main([*common, "--status", "proposed"])
|
|
263
|
+
self._run_main([*common, "--status", "confirmed", "--reviewer", "human@example.test"])
|
|
264
|
+
|
|
265
|
+
payload = build_payload(root, root / "work" / "sessions")
|
|
266
|
+
self.assertEqual(2, payload["summary"]["recoveries"])
|
|
267
|
+
self.assertEqual(
|
|
268
|
+
["proposed", "confirmed"],
|
|
269
|
+
[item["status"] for item in payload["recoveries"]],
|
|
270
|
+
)
|
|
271
|
+
html = _html_page(payload)
|
|
272
|
+
self.assertIn('data-panel="recovery"', html)
|
|
273
|
+
self.assertIn('id="recovery"', html)
|
|
274
|
+
self.assertIn("Resume location", html)
|
|
275
|
+
self.assertIn("after reconcile", html)
|
|
276
|
+
self.assertIn("human@example.test", html)
|
|
277
|
+
self.assertIn("Executable action", html)
|
|
278
|
+
self.assertIn("Verification", html)
|
|
279
|
+
self.assertIn("Max attempts", html)
|
|
280
|
+
|
|
281
|
+
def test_dashboard_aggregates_runs_by_prompt_flow(self) -> None:
|
|
282
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
283
|
+
root = Path(tmp)
|
|
284
|
+
first = root / "work" / "sessions" / "root.md"
|
|
285
|
+
second = root / "work" / "sessions" / "child.md"
|
|
286
|
+
for out, run_id, parent, work_item in (
|
|
287
|
+
(first, "11111111-1111-4111-8111-111111111111", None, None),
|
|
288
|
+
(second, "22222222-2222-4222-8222-222222222222", "11111111-1111-4111-8111-111111111111", "WI-002"),
|
|
289
|
+
):
|
|
290
|
+
args = [
|
|
291
|
+
"workflow", "run", "--task", "Flow node", "--out", str(out),
|
|
292
|
+
"--run-id", run_id, "--flow-id", "FLOW-001",
|
|
293
|
+
"--root-run-id", "11111111-1111-4111-8111-111111111111",
|
|
294
|
+
"--use-default-completion-conditions",
|
|
295
|
+
]
|
|
296
|
+
if parent:
|
|
297
|
+
args.extend(["--parent-run-id", parent, "--work-item-id", work_item])
|
|
298
|
+
self._run_main(args)
|
|
299
|
+
|
|
300
|
+
payload = build_payload(root, root / "work" / "sessions")
|
|
301
|
+
assert payload["summary"]["flows"] == 1
|
|
302
|
+
flow = payload["flows"][0]
|
|
303
|
+
assert flow["flow_id"] == "FLOW-001"
|
|
304
|
+
assert flow["root_run_id"] == "11111111-1111-4111-8111-111111111111"
|
|
305
|
+
assert flow["state"] == "blocked"
|
|
306
|
+
assert set(flow["run_ids"]) == {
|
|
307
|
+
"11111111-1111-4111-8111-111111111111",
|
|
308
|
+
"22222222-2222-4222-8222-222222222222",
|
|
309
|
+
}
|
|
310
|
+
child = next(run for run in payload["runs"] if run["run_id"] == "22222222-2222-4222-8222-222222222222")
|
|
311
|
+
assert child["parent_run_id"] == "11111111-1111-4111-8111-111111111111"
|
|
312
|
+
assert child["work_item_id"] == "WI-002"
|
|
313
|
+
|
|
314
|
+
def test_workflow_delegate_starts_child_skill_and_records_parent_flow_trace(self) -> None:
|
|
315
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
316
|
+
root = Path(tmp)
|
|
317
|
+
self._write_valid_skill(root)
|
|
318
|
+
parent = root / "work" / "sessions" / "parent.md"
|
|
319
|
+
child = root / "work" / "sessions" / "child.md"
|
|
320
|
+
self._run_main([
|
|
321
|
+
"workflow", "run", "--task", "Delegate one item", "--out", str(parent),
|
|
322
|
+
"--run-id", "11111111-1111-4111-8111-111111111111",
|
|
323
|
+
"--flow-id", "FLOW-002", "--use-default-completion-conditions",
|
|
324
|
+
])
|
|
325
|
+
self._run_main([
|
|
326
|
+
"workflow", "delegate", "--root", str(root), "--parent-log", str(parent), "--meta", "skills/sample/meta.md",
|
|
327
|
+
"--task", "Execute delegated item", "--out", str(child),
|
|
328
|
+
"--run-id", "22222222-2222-4222-8222-222222222222", "--work-item-id", "WI-002",
|
|
329
|
+
])
|
|
330
|
+
parent_text = parent.read_text(encoding="utf-8")
|
|
331
|
+
child_text = child.read_text(encoding="utf-8")
|
|
332
|
+
assert '"event":"child_run.started"' in parent_text
|
|
333
|
+
assert "- flow_id: `FLOW-002`" in child_text
|
|
334
|
+
assert "- parent_run_id: `11111111-1111-4111-8111-111111111111`" in child_text
|
|
335
|
+
assert "- work_item_id: `WI-002`" in child_text
|
|
336
|
+
|
|
337
|
+
def test_prompt_flow_supports_multiple_delegated_work_items(self) -> None:
|
|
338
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
339
|
+
root = Path(tmp)
|
|
340
|
+
self._write_valid_skill(root)
|
|
341
|
+
parent = root / "work" / "sessions" / "parent.md"
|
|
342
|
+
children = [root / "work" / "sessions" / "child-a.md", root / "work" / "sessions" / "child-b.md"]
|
|
343
|
+
self._run_main([
|
|
344
|
+
"workflow", "run", "--task", "Mixed prompt", "--out", str(parent),
|
|
345
|
+
"--run-id", "11111111-1111-4111-8111-111111111111", "--flow-id", "FLOW-MULTI",
|
|
346
|
+
"--use-default-completion-conditions",
|
|
347
|
+
])
|
|
348
|
+
for index, child in enumerate(children, start=1):
|
|
349
|
+
self._run_main([
|
|
350
|
+
"workflow", "delegate", "--root", str(root), "--parent-log", str(parent),
|
|
351
|
+
"--meta", "skills/sample/meta.md", "--task", f"Execute item {index}",
|
|
352
|
+
"--out", str(child), "--run-id", f"{index + 1:08d}-2222-4222-8222-222222222222",
|
|
353
|
+
"--work-item-id", f"WI-00{index}",
|
|
354
|
+
])
|
|
355
|
+
|
|
356
|
+
payload = build_payload(root, root / "work" / "sessions")
|
|
357
|
+
flow = next(flow for flow in payload["flows"] if flow["flow_id"] == "FLOW-MULTI")
|
|
358
|
+
assert len(flow["run_ids"]) == 3
|
|
359
|
+
parent_run = next(run for run in flow["runs"] if run["run_id"] == "11111111-1111-4111-8111-111111111111")
|
|
360
|
+
assert len([event for event in parent_run["observation_events"] if event.get("event") == "child_run.started"]) == 2
|
|
361
|
+
assert {run["work_item_id"] for run in flow["runs"] if run["parent_run_id"]} == {"WI-001", "WI-002"}
|
|
362
|
+
|
|
363
|
+
def test_quality_review_routes_selected_skill_and_starts_child(self) -> None:
|
|
364
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
365
|
+
root = Path(tmp)
|
|
366
|
+
self._write_valid_skill(root)
|
|
367
|
+
parent = root / "work" / "sessions" / "parent.md"
|
|
368
|
+
child = root / "work" / "sessions" / "quality.md"
|
|
369
|
+
self._run_main([
|
|
370
|
+
"workflow", "run", "--task", "Review flow", "--out", str(parent),
|
|
371
|
+
"--run-id", "11111111-1111-4111-8111-111111111111",
|
|
372
|
+
"--flow-id", "FLOW-QUALITY", "--use-default-completion-conditions",
|
|
373
|
+
])
|
|
374
|
+
self._run_main([
|
|
375
|
+
"workflow", "quality-review", "--root", str(root), "--parent-log", str(parent),
|
|
376
|
+
"--meta", "skills/sample/meta.md", "--selected-skill", "sample_skill",
|
|
377
|
+
"--candidate", "sample_skill", "--reason", "The output requires the selected review capability",
|
|
378
|
+
"--task", "Review the output", "--out", str(child), "--work-item-id", "WI-001",
|
|
379
|
+
])
|
|
380
|
+
parent_text = parent.read_text(encoding="utf-8")
|
|
381
|
+
child_text = child.read_text(encoding="utf-8")
|
|
382
|
+
assert '"selection_mode":"quality_review"' in parent_text
|
|
383
|
+
assert '"event":"child_run.started"' in parent_text
|
|
384
|
+
assert "- flow_id: `FLOW-QUALITY`" in child_text
|
|
385
|
+
assert "- work_item_id: `WI-001`" in child_text
|
|
386
|
+
|
|
244
387
|
def test_dashboard_clears_missing_information_when_observability_is_recorded(self) -> None:
|
|
245
388
|
with tempfile.TemporaryDirectory() as tmp:
|
|
246
389
|
root = Path(tmp)
|
|
@@ -403,6 +546,7 @@ class DashboardTests(unittest.TestCase):
|
|
|
403
546
|
html = _html_page(build_payload(root, root / "work" / "sessions"))
|
|
404
547
|
|
|
405
548
|
self.assertIn('data-panel="overview"', html)
|
|
549
|
+
self.assertIn('data-panel="flows"', html)
|
|
406
550
|
self.assertIn('data-panel="attention"', html)
|
|
407
551
|
self.assertIn('data-panel="closure"', html)
|
|
408
552
|
self.assertIn('data-panel="evidence"', html)
|
|
@@ -411,6 +555,15 @@ class DashboardTests(unittest.TestCase):
|
|
|
411
555
|
self.assertIn('data-panel="analysis"', html)
|
|
412
556
|
self.assertIn('data-panel="missing-information"', html)
|
|
413
557
|
self.assertIn('id="overview"', html)
|
|
558
|
+
self.assertIn('id="flows"', html)
|
|
559
|
+
self.assertIn("Execution tree", html)
|
|
560
|
+
self.assertIn("Flow details", html)
|
|
561
|
+
self.assertIn("Work Item", html)
|
|
562
|
+
self.assertIn("Minimum intake", html)
|
|
563
|
+
self.assertIn("State", html)
|
|
564
|
+
self.assertIn("Execution records", html)
|
|
565
|
+
self.assertIn("Activity", html)
|
|
566
|
+
self.assertIn("Evidence and concerns", html)
|
|
414
567
|
self.assertIn('id="attention"', html)
|
|
415
568
|
self.assertIn('id="closure"', html)
|
|
416
569
|
self.assertIn('id="evidence"', html)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from xrefkit.host_precheck import build_precheck_report
|
|
5
|
+
from xrefkit.__main__ import main
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _spec(**overrides):
|
|
9
|
+
value = {
|
|
10
|
+
"host": "Codex Desktop 1.2",
|
|
11
|
+
"extension": "XRefKit extension 0.4.8",
|
|
12
|
+
"transcript_reference": "human-run/transcript-001",
|
|
13
|
+
"baseline": {"skill": "brownfield_workflow", "result": "managed"},
|
|
14
|
+
"observed": {"skill": "brownfield_workflow", "result": "managed"},
|
|
15
|
+
"evidence": {"bootstrap": True, "discovery": True, "route_selection": True},
|
|
16
|
+
"catalog": "available",
|
|
17
|
+
"intent": "clear",
|
|
18
|
+
}
|
|
19
|
+
value.update(overrides)
|
|
20
|
+
return value
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_precheck_passes_only_with_observable_managed_route_evidence():
|
|
24
|
+
report = build_precheck_report(_spec())
|
|
25
|
+
assert report["schema"] == "xrefkit.host_compatibility_precheck/v1"
|
|
26
|
+
assert report["assessment"]["status"] == "pass"
|
|
27
|
+
assert "private model reasoning" in report["unobservable"]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_precheck_blocks_generic_preselection_without_claiming_override():
|
|
31
|
+
report = build_precheck_report(_spec(generic_preselection=True))
|
|
32
|
+
assert report["assessment"]["status"] == "blocked"
|
|
33
|
+
assert "explicit XRefKit entrypoint" in report["assessment"]["next_action"]
|
|
34
|
+
assert any("whether XRefKit overrode" in item for item in report["unobservable"])
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_precheck_distinguishes_missing_catalog_and_ambiguous_intent():
|
|
38
|
+
assert build_precheck_report(_spec(catalog="unavailable"))["assessment"]["status"] == "blocked"
|
|
39
|
+
assert build_precheck_report(_spec(intent="ambiguous"))["assessment"]["status"] == "needs_human_confirmation"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_precheck_cli_writes_repeatable_json_report(tmp_path: Path, capsys):
|
|
43
|
+
source = tmp_path / "input.json"
|
|
44
|
+
output = tmp_path / "report.json"
|
|
45
|
+
source.write_text(json.dumps(_spec()), encoding="utf-8")
|
|
46
|
+
assert main(["host", "precheck", "--input", str(source), "--out", str(output)]) == 0
|
|
47
|
+
report = json.loads(output.read_text(encoding="utf-8"))
|
|
48
|
+
assert report["assessment"]["status"] == "pass"
|
|
49
|
+
assert json.loads(capsys.readouterr().out)["schema"] == report["schema"]
|