External integrations connect OpenClaw-env-manager to tool ecosystems such as OpenRouter and Cisco Skill Scanner.
openenv.integrations¶
openenv.integrations
¶
External integration modules.
openenv.integrations.scanner¶
openenv.integrations.scanner
¶
Skill scanner integration for OpenClawenv.
materialize_skills(manifest, target_dir)
¶
Write inline skills to a directory tree consumable by skill-scanner.
Source code in src/openenv/integrations/scanner.py
def materialize_skills(manifest: Manifest, target_dir: str | Path) -> Path:
"""Write inline skills to a directory tree consumable by skill-scanner."""
skills_root = Path(target_dir)
skills_root.mkdir(parents=True, exist_ok=True)
for skill in manifest.skills:
skill_dir = skills_root / skill.name
skill_dir.mkdir(parents=True, exist_ok=True)
(skill_dir / "SKILL.md").write_text(
skill.rendered_content(
state_dir=manifest.openclaw.state_dir,
workspace=manifest.openclaw.workspace,
),
encoding="utf-8",
)
for relative_path, content in sorted(skill.assets.items()):
asset_path = skill_dir / relative_path
asset_path.parent.mkdir(parents=True, exist_ok=True)
asset_path.write_text(
rewrite_openclaw_home_paths(
content,
state_dir=manifest.openclaw.state_dir,
workspace=manifest.openclaw.workspace,
),
encoding="utf-8",
)
return skills_root
run_skill_scanner(manifest_path, manifest, *, scanner_bin='skill-scanner', scanner_args=None, keep_artifacts=False)
¶
Materialize skills and invoke the external skill-scanner CLI.
Source code in src/openenv/integrations/scanner.py
def run_skill_scanner(
manifest_path: str | Path,
manifest: Manifest,
*,
scanner_bin: str = "skill-scanner",
scanner_args: list[str] | None = None,
keep_artifacts: bool = False,
) -> Path | None:
"""Materialize skills and invoke the external skill-scanner CLI."""
manifest_root = Path(manifest_path).resolve().parent
extra_args = list(scanner_args or [])
if extra_args and extra_args[0] == "--":
extra_args = extra_args[1:]
scan_root = manifest_root / f"openclawenv-scan-tmp-{uuid.uuid4().hex}"
scan_root.mkdir(parents=True, exist_ok=False)
try:
skills_root = materialize_skills(manifest, scan_root / "skills")
command = [scanner_bin, "scan-all", str(skills_root), "--recursive", *extra_args]
try:
subprocess.run(command, check=True, cwd=manifest_root)
except OSError as exc:
raise CommandError(
"skill-scanner is not available on PATH. "
"Install it with `pip install .[scan]` or provide --scanner-bin."
) from exc
except subprocess.CalledProcessError as exc:
raise CommandError(
f"skill-scanner failed with exit code {exc.returncode}.",
exit_code=exc.returncode,
) from exc
if keep_artifacts:
destination = manifest_root / ".openclawenv-scan"
if destination.exists():
shutil.rmtree(destination, ignore_errors=True)
shutil.copytree(scan_root, destination)
return destination
finally:
shutil.rmtree(scan_root, ignore_errors=True)
return None
openenv.integrations.openrouter¶
openenv.integrations.openrouter
¶
OpenRouter integration for improving bot markdown documents with tool calling.
improve_markdown_documents_with_openrouter(*, api_key, bot_name, context_payload, instruction, write_document, model=None, output_language=DEFAULT_OUTPUT_LANGUAGE, batch_size=DEFAULT_DOCUMENT_BATCH_SIZE)
¶
Use OpenRouter tool calling to inspect and rewrite bot markdown files.
Source code in src/openenv/integrations/openrouter.py
def improve_markdown_documents_with_openrouter(
*,
api_key: str,
bot_name: str,
context_payload: dict[str, Any],
instruction: str,
write_document: Callable[[str, str], None],
model: str | None = None,
output_language: str = DEFAULT_OUTPUT_LANGUAGE,
batch_size: int = DEFAULT_DOCUMENT_BATCH_SIZE,
) -> str:
"""Use OpenRouter tool calling to inspect and rewrite bot markdown files."""
documents = context_payload.get("documents")
if not isinstance(documents, dict):
raise OpenEnvError("context_payload.documents must be an object mapping files to text.")
if batch_size < 1:
raise OpenEnvError("batch_size must be at least 1.")
working_context = _clone_context_payload(context_payload)
allowed_files = sorted(working_context["documents"].keys())
if not allowed_files:
return "No markdown documents were available for improvement."
batches = list(_document_batches(allowed_files, batch_size))
summaries: list[str] = []
def tracked_write_document(file_name: str, content: str) -> None:
"""Persist one updated file and refresh the working context for later batches."""
write_document(file_name, content)
working_context["documents"][file_name] = content
for index, batch_files in enumerate(batches, start=1):
batch_context = _context_payload_for_batch(
working_context,
batch_files=batch_files,
batch_index=index,
total_batches=len(batches),
)
summary = _improve_markdown_documents_batch(
api_key=api_key,
bot_name=bot_name,
context_payload=batch_context,
instruction=instruction,
write_document=tracked_write_document,
model=model,
output_language=output_language,
)
if summary:
summaries.append(summary)
if len(summaries) == 1:
return summaries[0]
return " | ".join(
f"Batch {index}: {summary}" for index, summary in enumerate(summaries, start=1)
)