forked from molecule-ai/molecule-core
Renames: - platform/ → workspace-server/ (Go module path stays as "platform" for external dep compat — will update after plugin module republish) - workspace-template/ → workspace/ Removed (moved to separate repos or deleted): - PLAN.md — internal roadmap (move to private project board) - HANDOFF.md, AGENTS.md — one-time internal session docs - .claude/ — gitignored entirely (local agent config) - infra/cloudflare-worker/ → Molecule-AI/molecule-tenant-proxy - org-templates/molecule-dev/ → standalone template repo - .mcp-eval/ → molecule-mcp-server repo - test-results/ — ephemeral, gitignored Security scrubbing: - Cloudflare account/zone/KV IDs → placeholders - Real EC2 IPs → <EC2_IP> in all docs - CF token prefix, Neon project ID, Fly app names → redacted - Langfuse dev credentials → parameterized - Personal runner username/machine name → generic Community files: - CONTRIBUTING.md — build, test, branch conventions - CODE_OF_CONDUCT.md — Contributor Covenant 2.1 All Dockerfiles, CI workflows, docker-compose, railway.toml, render.yaml, README, CLAUDE.md updated for new directory names. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
75 lines
2.9 KiB
Python
75 lines
2.9 KiB
Python
"""AGENTS.md auto-generation for Molecule AI workspaces.
|
|
|
|
Implements the AAIF / Linux Foundation AGENTS.md standard so that peer agents
|
|
and orchestration tools can discover this workspace's identity, role, A2A
|
|
endpoint, and available tools without reading the full system prompt.
|
|
|
|
Usage::
|
|
|
|
from agents_md import generate_agents_md
|
|
|
|
generate_agents_md(config_dir="/configs", output_path="/workspace/AGENTS.md")
|
|
|
|
The function is called automatically at container startup (see main.py).
|
|
"""
|
|
|
|
import logging
|
|
import os
|
|
from pathlib import Path
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def generate_agents_md(config_dir: str, output_path: str) -> None:
|
|
"""Generate (or regenerate) AGENTS.md from the workspace config.yaml.
|
|
|
|
Always overwrites ``output_path`` — no stale-file guard. Re-calling
|
|
after editing config.yaml produces a fresh file reflecting the changes.
|
|
|
|
Args:
|
|
config_dir: Directory containing config.yaml (same convention as
|
|
``load_config`` in config.py).
|
|
output_path: Absolute path where AGENTS.md will be written.
|
|
The parent directory is expected to exist.
|
|
"""
|
|
from config import load_config
|
|
|
|
cfg = load_config(config_dir)
|
|
|
|
# ── A2A Endpoint ─────────────────────────────────────────────────────────
|
|
# AGENT_URL env var takes priority (production deployments behind a proxy).
|
|
# Otherwise derive from the configured a2a.port (default 8000).
|
|
endpoint = os.environ.get("AGENT_URL") or f"http://localhost:{cfg.a2a.port}/a2a"
|
|
|
|
# ── Role ─────────────────────────────────────────────────────────────────
|
|
# Fall back to description when the role field is absent so legacy
|
|
# config.yaml files (without a role key) still produce meaningful output.
|
|
role = cfg.role if cfg.role else cfg.description
|
|
|
|
# ── MCP Tools ────────────────────────────────────────────────────────────
|
|
# tools (skill names) + plugins (installed plugin names) form the combined
|
|
# capability surface visible to peer agents.
|
|
all_tools = list(cfg.tools) + list(cfg.plugins)
|
|
if all_tools:
|
|
tools_section = "\n".join(f"- {t}" for t in all_tools)
|
|
else:
|
|
tools_section = "None"
|
|
|
|
content = (
|
|
f"# {cfg.name}\n"
|
|
f"\n"
|
|
f"**Role:** {role}\n"
|
|
f"\n"
|
|
f"## Description\n"
|
|
f"{cfg.description}\n"
|
|
f"\n"
|
|
f"## A2A Endpoint\n"
|
|
f"{endpoint}\n"
|
|
f"\n"
|
|
f"## MCP Tools\n"
|
|
f"{tools_section}\n"
|
|
)
|
|
|
|
Path(output_path).write_text(content, encoding="utf-8")
|
|
logger.info("Generated AGENTS.md at %s for workspace %r", output_path, cfg.name)
|