2020
2121
2222SCHEMA_VERSION = "loopx_agent_onboarding_v0"
23+ HOST_SKILL_DELIVERY_SCHEMA_VERSION = "loopx_host_skill_delivery_v0"
24+ REQUIRED_HOST_SKILL_IDS = [
25+ "loopx-project" ,
26+ "loopx-pr-review" ,
27+ "loopx-doc-registry" ,
28+ "loopx-self-repair" ,
29+ ]
2330
2431
2532def _surface_install_command (agent_type : str , cli_bin : str ) -> str | None :
@@ -35,6 +42,52 @@ def _surface_install_command(agent_type: str, cli_bin: str) -> str | None:
3542 return None
3643
3744
45+ def _skill_delivery_contract (agent_type : str ) -> dict [str , Any ]:
46+ if agent_type != "other-agent" :
47+ return {
48+ "schema_version" : HOST_SKILL_DELIVERY_SCHEMA_VERSION ,
49+ "mode" : "surface_managed" ,
50+ "owner" : "loopx_surface_installer" ,
51+ "codex_skills_root_required" : agent_type .startswith ("codex-" ),
52+ "host_readback_required" : False ,
53+ }
54+ return {
55+ "schema_version" : HOST_SKILL_DELIVERY_SCHEMA_VERSION ,
56+ "mode" : "host_managed" ,
57+ "owner" : "custom_agent_host" ,
58+ "status" : "pending_host_readback" ,
59+ "codex_skills_root_required" : False ,
60+ "required_for_cli_health" : False ,
61+ "required_for_loopx_workflow" : True ,
62+ "required_skill_ids" : REQUIRED_HOST_SKILL_IDS ,
63+ "delivery_options" : [
64+ "host_skill_manifest" ,
65+ "prompt_injection" ,
66+ ],
67+ "source_repository" : "https://github.com/huangruiteng/loopx" ,
68+ "source_directories" : [
69+ f"skills/{ skill_id } " for skill_id in REQUIRED_HOST_SKILL_IDS
70+ ],
71+ "source_contract" : (
72+ "Use the same LoopX release or repository revision as the CLI when "
73+ "materializing skills or injecting equivalent SKILL.md instructions "
74+ "through the custom host."
75+ ),
76+ "host_readback_required" : True ,
77+ "readback_fields" : [
78+ "integration_mode" ,
79+ "loaded_skill_ids" ,
80+ "source_revision" ,
81+ ],
82+ "success_criteria" : [
83+ "the host reports which integration mode it selected" ,
84+ "the host reports every required LoopX skill id as loaded" ,
85+ "the host reports the source revision or digest used for delivery" ,
86+ "no Codex-specific skill directory is assumed" ,
87+ ],
88+ }
89+
90+
3891def _bootstrap_pack_command (
3992 * ,
4093 project : str ,
@@ -86,7 +139,11 @@ def _start_instruction(agent_type: str) -> str:
86139 return "Run `/loopx <task>`; after todo writeback, call `loopx_goal_activate` with the generated heartbeat task body."
87140 if agent_type == "manual" :
88141 return "Use the CLI packet and wire an external scheduler, or run quota/status/todo commands manually."
89- return "Use the host's explicit LoopX command facade such as `@loopx <task>` or `$loopx <task>`, then wire its scheduler through this packet."
142+ return (
143+ "Deliver the required LoopX skills through the custom host and verify its "
144+ "loaded-skill readback; then use the host's explicit LoopX command facade "
145+ "and wire its scheduler through this packet."
146+ )
90147
91148
92149def build_agent_onboarding_packet (
@@ -132,7 +189,10 @@ def build_agent_onboarding_packet(
132189 available_capabilities = normalized_available_capabilities ,
133190 )
134191 commands : dict [str , Any ] = {
135- "doctor_or_install" : render_codex_cli_no_clone_preflight (cli_bin = cli_bin ),
192+ "doctor_or_install" : render_codex_cli_no_clone_preflight (
193+ cli_bin = cli_bin ,
194+ doctor_agent_type = canonical_agent_type ,
195+ ),
136196 "bootstrap_command_pack" : bootstrap_pack_command ,
137197 "quota_guard" : (
138198 render_quota_guard_command (
@@ -184,6 +244,7 @@ def build_agent_onboarding_packet(
184244 "task_text" : task_text ,
185245 "project_connection" : inspection ,
186246 "host_loop_activation" : host_loop_activation ,
247+ "skill_delivery" : _skill_delivery_contract (canonical_agent_type ),
187248 "recommended_start" : (
188249 "Select one registered agent lane from identity_selection_gate, then rerun onboarding."
189250 if not activation_allowed
@@ -207,6 +268,13 @@ def build_agent_onboarding_packet(
207268 "setup_complete_requires" : [
208269 "project-local LoopX state exists or was intentionally previewed" ,
209270 "ordered todos are written when task text was supplied" ,
271+ * (
272+ [
273+ "custom host loaded-skill readback satisfies skill_delivery.success_criteria"
274+ ]
275+ if canonical_agent_type == "other-agent"
276+ else []
277+ ),
210278 "host_loop_activation success criteria are satisfied or a concrete gate is reported" ,
211279 ],
212280 },
@@ -230,6 +298,11 @@ def render_agent_onboarding_markdown(payload: dict[str, Any]) -> str:
230298 )
231299 identity_gate = payload .get ("identity_selection_gate" )
232300 identity_gate = identity_gate if isinstance (identity_gate , dict ) else {}
301+ skill_delivery = (
302+ payload .get ("skill_delivery" )
303+ if isinstance (payload .get ("skill_delivery" ), dict )
304+ else {}
305+ )
233306 lines = [
234307 "# LoopX Agent Onboarding" ,
235308 "" ,
@@ -247,6 +320,24 @@ def render_agent_onboarding_markdown(payload: dict[str, Any]) -> str:
247320 ]
248321 if commands .get ("install_command_facade" ):
249322 lines .extend (["" , "```bash" , str (commands .get ("install_command_facade" )), "```" ])
323+ if skill_delivery .get ("mode" ) == "host_managed" :
324+ lines .extend (
325+ [
326+ "" ,
327+ "## Host-Managed Skill Delivery" ,
328+ "" ,
329+ f"- owner: `{ skill_delivery .get ('owner' )} `" ,
330+ f"- required_for_cli_health: `{ skill_delivery .get ('required_for_cli_health' )} `" ,
331+ f"- required_for_loopx_workflow: `{ skill_delivery .get ('required_for_loopx_workflow' )} `" ,
332+ f"- delivery_options: `{ ',' .join (skill_delivery .get ('delivery_options' ) or [])} `" ,
333+ f"- required_skill_ids: `{ ',' .join (skill_delivery .get ('required_skill_ids' ) or [])} `" ,
334+ f"- source_repository: `{ skill_delivery .get ('source_repository' )} `" ,
335+ f"- source_directories: `{ ',' .join (skill_delivery .get ('source_directories' ) or [])} `" ,
336+ f"- host_readback_required: `{ skill_delivery .get ('host_readback_required' )} `" ,
337+ f"- readback_fields: `{ ',' .join (skill_delivery .get ('readback_fields' ) or [])} `" ,
338+ f"- source_contract: { skill_delivery .get ('source_contract' )} " ,
339+ ]
340+ )
250341 lines .extend (["" , "```bash" , str (commands .get ("bootstrap_command_pack" ) or "" ), "```" ])
251342 if commands .get ("codex_cli_bootstrap_message" ):
252343 lines .extend (["" , "```bash" , str (commands .get ("codex_cli_bootstrap_message" )), "```" ])
0 commit comments