(self, plugin: PluginSource, agent: AgentSource, result: EmitResult)
| 479 | result.written.append(self.mirror_file(ref, skill_dir / "references" / rel)) |
| 480 | |
| 481 | def _emit_agent(self, plugin: PluginSource, agent: AgentSource, result: EmitResult) -> None: |
| 482 | agent_id = f"{plugin.name}__{agent.name}" |
| 483 | rel = Path(".codex") / "agents" / f"{agent_id}.toml" |
| 484 | |
| 485 | # Map model alias; warn if the source model isn't one of the known aliases. |
| 486 | model, warning = resolve_model("codex", agent.model) |
| 487 | if warning: |
| 488 | result.warnings.append(f"agent `{agent_id}`: {warning}") |
| 489 | |
| 490 | # Heuristic for sandbox_mode: |
| 491 | # - If source frontmatter has NO `tools:` field at all -> agent has all tools by |
| 492 | # default in Claude Code -> map to workspace-write (permissive). |
| 493 | # - If source has `tools:` (even empty) and all listed tools are read-ish -> read-only. |
| 494 | # - Otherwise (mix of read/write tools) -> workspace-write. |
| 495 | ro_tools = {"Read", "Glob", "Grep", "WebFetch", "WebSearch"} |
| 496 | has_tools_field = "tools" in agent.frontmatter |
| 497 | if not has_tools_field: |
| 498 | sandbox_mode = "workspace-write" # Claude default: unrestricted |
| 499 | elif set(agent.tools).issubset(ro_tools): |
| 500 | # Explicit allowlist constrained to read-only tools (or `tools: []` — even more restrictive) |
| 501 | sandbox_mode = "read-only" |
| 502 | else: |
| 503 | sandbox_mode = "workspace-write" |
| 504 | |
| 505 | developer_instructions = _rewrite_body_for_codex(agent.body).strip() |
| 506 | if not developer_instructions: |
| 507 | developer_instructions = agent.description or f"{agent_id} subagent." |
| 508 | |
| 509 | lines = [ |
| 510 | _toml_kv("name", agent_id), |
| 511 | _toml_kv("description", agent.description or f"{agent.name} (from {plugin.name})"), |
| 512 | _toml_kv("model", model), |
| 513 | _toml_kv("sandbox_mode", sandbox_mode), |
| 514 | _toml_kv("developer_instructions", developer_instructions), |
| 515 | ] |
| 516 | if agent.name in {"default", "worker", "explorer"}: |
| 517 | result.warnings.append( |
| 518 | f"agent `{agent.name}` collides with Codex built-in role; emitted as `{agent_id}` instead." |
| 519 | ) |
| 520 | |
| 521 | result.written.append(self.write(rel, "\n".join(lines) + "\n")) |
| 522 | |
| 523 | def _emit_command_as_skill( |
| 524 | self, |
no test coverage detected