#!/usr/bin/env python3
"""Scaffold a buildable Bring Your Own Context workspace and a working MCP server."""

from __future__ import annotations

import argparse
import shutil
import textwrap
from pathlib import Path

MANIFEST = """version: 1
context_system_name: \"{name}\"
ownership_mode: \"{ownership}\"
primary_actor: \"replace-me\"
primary_goal: \"{goal}\"
portability_target:
  source_runtime: \"{source_runtime}\"
  target_runtime: \"{target_runtime}\"
  export_format: \"typed markdown objects plus bundle manifest\"
interfaces:
  - type: \"mcp\"
    status: \"active\"
    entrypoint: \"./mcp_server/server.py\"
  - type: \"filesystem\"
    status: \"active\"
    entrypoint: \"./memory_objects\"
context_components:
  context_vault:
    storage_backend: \"filesystem\"
    owner: \"{owner_label}\"
    path: \"./memory_objects\"
  artifact_store:
    enabled: true
    location: \"./artifacts\"
  retrieval_router:
    strategy: \"just_in_time\"
    token_budget: \"define-me\"
    freshness_policy: \"define-me\"
  writeback_engine:
    enabled: true
    review_required: true
  policy_layer:
    deletion_supported: true
    export_supported: true
    audit_logging: true
  mcp_server:
    implementation: \"FastMCP Python server\"
    default_transport: \"{transport_default}\"
    requirements_file: \"./mcp_server/requirements.txt\"
    bundle_builder: \"./tools/build_context_bundle.py\"
memory_taxonomy:
  - type: identity
    enabled: true
    retrieval_form: summary
  - type: preference
    enabled: true
    retrieval_form: preference_sheet
  - type: workflow
    enabled: true
    retrieval_form: checklist
  - type: domain
    enabled: true
    retrieval_form: retrieval_chunk
  - type: relationship
    enabled: true
    retrieval_form: behavioral_contract
  - type: artifact
    enabled: true
    retrieval_form: link_or_summary
  - type: execution
    enabled: true
    retrieval_form: state_object
  - type: evaluative
    enabled: true
    retrieval_form: scorecard
routing_rules:
  default_task:
    retrieve:
      - identity
      - preference
      - workflow
feedback_loop:
  enabled: true
  log_file: \"./feedback_log.md\"
notes: |
  This workspace was generated by portable-context-os.
  It includes both the context vault and a working MCP server scaffold.
"""

GOVERNANCE = """# Governance Policy for {name}

## Scope

Describe whether this system governs personal, team, or enterprise context.

## Creation and review rules

Document who can create durable memory, what needs review, and what must never be stored.

## Access rules

Document who can read, write, delete, or export each memory class.

## Retention and deletion

Document deletion propagation, tombstones, recovery rules, and bundle revocation.

## Audit trail

Document how retrieval, writeback, deletion, and export events are recorded.
"""

SCORECARD = """# Evaluation Scorecard: {name}

## Summary

Write a one-paragraph evaluation summary.

## Metric table

| Metric | Current value | Target | Notes |
|---|---:|---:|---|
| cold-start reduction | TBD | TBD | |
| retrieval precision | TBD | TBD | |
| retrieval noise rate | TBD | TBD | |
| portability success rate | TBD | TBD | |
| memory edit acceptance rate | TBD | TBD | |
| delete integrity | TBD | TBD | |
| governance exceptions | TBD | TBD | |

## Feedback-loop observations

| Loop item | Observation | Planned fix |
|---|---|---|
| Retrieval misses | TBD | TBD |
| Memory corruption risks | TBD | TBD |
| Governance failures | TBD | TBD |
| Portability failures | TBD | TBD |
"""

MEMORY_OBJECT = """# Memory Object: example-preference

## Identity

| Field | Value |
|---|---|
| Object ID | example-preference |
| Memory type | preference |
| Owner scope | {ownership} |
| Source | human input |
| Status | draft |
| Last updated | YYYY-MM-DD |

## Content

Describe one durable preference or workflow here.

## Retrieval contract

| Rule | Value |
|---|---|
| Retrieval trigger | define-me |
| Retrieval form | preference_sheet |
| Freshness rule | define-me |
| Confidence threshold | 0.8 |
| Max retrieval scope | 1 object |

## Writeback contract

| Rule | Value |
|---|---|
| Writeback trigger | confirmed preference |
| Human review required | yes |
| Deprecation rule | define-me |
| Deletion path | define-me |

## Governance notes

Document sharing, redaction, retention, and ownership constraints here.

## Evidence and linked artifacts

List supporting files, chats, or outputs here.
"""

README = """# Portable Context Workspace

This workspace was scaffolded by `init_context_os.py` from the `portable-context-os` skill.

## What this workspace already includes

| Component | Path | Purpose |
|---|---|---|
| Context manifest | `context_manifest.yaml` | Declares ownership, interfaces, routing, and runtime shape |
| Governance policy | `governance_policy.md` | Captures review, access, retention, deletion, and export rules |
| Evaluation scorecard | `eval_scorecard.md` | Tracks retrieval quality, portability, and trust metrics |
| Memory objects | `memory_objects/` | Stores typed durable memory |
| Artifact store | `artifacts/` | Stores source artifacts and output artifacts |
| Bundle builder | `tools/build_context_bundle.py` | Rebuilds the portable bundle manifest |
| MCP server | `mcp_server/server.py` | Exposes the BYOC system over MCP |

## Recommended order

1. Edit `context_manifest.yaml`.
2. Edit `governance_policy.md`.
3. Add or refine memory objects in `memory_objects/`.
4. Add artifacts to `artifacts/`.
5. Install MCP runtime dependencies.
6. Run the generated MCP server.
7. Rebuild the portable bundle manifest.

## Runtime commands

### Install dependencies

```bash
python3.11 -m pip install -r mcp_server/requirements.txt
```

### Validate the server without starting it

```bash
python3.11 mcp_server/server.py --dry-run
```

### Run the server in STDIO mode

```bash
python3.11 mcp_server/server.py --transport stdio
```

### Run the server with streamable HTTP transport

```bash
python3.11 mcp_server/server.py --transport streamable-http
```

### Rebuild the bundle manifest

```bash
python3.11 tools/build_context_bundle.py .
```
"""

FEEDBACK_LOG = """# Context Feedback Log

Use this file to record retrieval misses, corruption risks, governance failures, and portability failures.

| Timestamp (UTC) | Category | Observation | Planned fix |
|---|---|---|---|
"""

SERVER_README = """# Portable Context MCP Server

This MCP server exposes a generated Bring Your Own Context workspace through tools, resources, and prompts.

## Exposed capabilities

| Surface | Purpose |
|---|---|
| Tools | Inspect, create, update, delete, and bundle typed memory objects |
| Resources | Read the manifest, bundle summary, and feedback log |
| Prompts | Review proposed durable-memory writebacks |

## Commands

### Dry run

```bash
python3.11 server.py --dry-run
```

### STDIO transport

```bash
python3.11 server.py --transport stdio
```

### Streamable HTTP transport

```bash
python3.11 server.py --transport streamable-http
```
"""

REQUIREMENTS = """mcp[cli]>=1.2.0
"""

ENV_EXAMPLE = """# Optional environment variables for the generated MCP server
PORTABLE_CONTEXT_WORKSPACE=..
"""

CLIENT_CONFIG = """{{
  \"mcpServers\": {{
    \"{server_slug}\": {{
      \"command\": \"python3.11\",
      \"args\": [
        \"{absolute_server_path}\",
        \"--transport\",
        \"stdio\"
      ]
    }}
  }}
}}
"""

STDIO_RUN = """#!/usr/bin/env bash
set -euo pipefail
python3.11 \"$(dirname \"$0\")/mcp_server/server.py\" --transport stdio
"""

HTTP_RUN = """#!/usr/bin/env bash
set -euo pipefail
python3.11 \"$(dirname \"$0\")/mcp_server/server.py\" --transport streamable-http
"""

SERVER_CODE = '''#!/usr/bin/env python3
from __future__ import annotations

import argparse
import json
import re
from datetime import datetime, timezone
from pathlib import Path
from typing import Any

from mcp.server.fastmcp import FastMCP

WORKSPACE_ROOT = Path(__file__).resolve().parent.parent
MANIFEST_PATH = WORKSPACE_ROOT / "context_manifest.yaml"
GOVERNANCE_PATH = WORKSPACE_ROOT / "governance_policy.md"
SCORECARD_PATH = WORKSPACE_ROOT / "eval_scorecard.md"
FEEDBACK_LOG_PATH = WORKSPACE_ROOT / "feedback_log.md"
MEMORY_DIR = WORKSPACE_ROOT / "memory_objects"
ARTIFACT_DIR = WORKSPACE_ROOT / "artifacts"
BUNDLE_DIR = WORKSPACE_ROOT / "bundles"
BUNDLE_PATH = BUNDLE_DIR / "context_bundle_manifest.json"
VALID_MEMORY_TYPES = {"identity", "preference", "workflow", "domain", "relationship", "artifact", "execution", "evaluative"}
SERVER_NAME = "__SERVER_NAME__"
DEFAULT_OWNER_SCOPE = "__DEFAULT_OWNER_SCOPE__"
DEFAULT_TRANSPORT = "__DEFAULT_TRANSPORT__"

mcp = FastMCP(SERVER_NAME, json_response=True, stateless_http=True)


def utc_now() -> str:
    return datetime.now(timezone.utc).isoformat()


def read_text(path: Path) -> str:
    return path.read_text(encoding="utf-8") if path.exists() else ""


def write_text(path: Path, text: str) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(text.rstrip() + "\\n", encoding="utf-8")


def slugify(value: str) -> str:
    slug = re.sub(r"[^a-zA-Z0-9_-]+", "-", value.strip()).strip("-").lower()
    return slug or "memory-object"


def extract_manifest_value(text: str, key: str, default: str = "unknown") -> str:
    match = re.search(rf"^{re.escape(key)}:\\s*\\\"?(.*?)\\\"?\\s*$", text, re.MULTILINE)
    return match.group(1).strip() if match else default


def load_manifest_summary() -> dict[str, str]:
    text = read_text(MANIFEST_PATH)
    return {
        "context_system_name": extract_manifest_value(text, "context_system_name"),
        "ownership_mode": extract_manifest_value(text, "ownership_mode"),
        "primary_goal": extract_manifest_value(text, "primary_goal"),
    }


def list_relative_files(base: Path) -> list[str]:
    if not base.exists():
        return []
    return [str(path.relative_to(WORKSPACE_ROOT)) for path in sorted(base.rglob("*")) if path.is_file()]


def parse_markdown_table(lines: list[str], heading: str) -> dict[str, str]:
    in_section = False
    table_lines: list[str] = []
    for line in lines:
        if line.strip() == heading:
            in_section = True
            continue
        if in_section and line.startswith("## "):
            break
        if in_section and line.strip().startswith("|"):
            table_lines.append(line.strip())
    rows: dict[str, str] = {}
    for raw_line in table_lines[2:]:
        parts = [part.strip() for part in raw_line.strip("|").split("|")]
        if len(parts) >= 2:
            rows[parts[0]] = parts[1]
    return rows


def extract_section(text: str, heading: str, next_headings: list[str]) -> str:
    marker = f"## {heading}"
    start = text.find(marker)
    if start == -1:
        return ""
    start += len(marker)
    tail = text[start:]
    end_positions = []
    for next_heading in next_headings:
        position = tail.find(f"## {next_heading}")
        if position != -1:
            end_positions.append(position)
    end = min(end_positions) if end_positions else len(tail)
    return tail[:end].strip()


def render_memory_object(data: dict[str, Any]) -> str:
    return f"""# Memory Object: {data['object_id']}

## Identity

| Field | Value |
|---|---|
| Object ID | {data['object_id']} |
| Memory type | {data['memory_type']} |
| Owner scope | {data['owner_scope']} |
| Source | {data['source']} |
| Status | {data['status']} |
| Last updated | {data['last_updated']} |

## Content

{data['content']}

## Retrieval contract

| Rule | Value |
|---|---|
| Retrieval trigger | {data['retrieval_trigger']} |
| Retrieval form | {data['retrieval_form']} |
| Freshness rule | {data['freshness_rule']} |
| Confidence threshold | {data['confidence_threshold']} |
| Max retrieval scope | {data['max_retrieval_scope']} |

## Writeback contract

| Rule | Value |
|---|---|
| Writeback trigger | {data['writeback_trigger']} |
| Human review required | {data['human_review_required']} |
| Deprecation rule | {data['deprecation_rule']} |
| Deletion path | {data['deletion_path']} |

## Governance notes

{data['governance_notes']}

## Evidence and linked artifacts

{data['evidence_and_linked_artifacts']}
"""


def parse_memory_object(path: Path) -> dict[str, Any]:
    text = read_text(path)
    lines = text.splitlines()
    identity = parse_markdown_table(lines, "## Identity")
    retrieval = parse_markdown_table(lines, "## Retrieval contract")
    writeback = parse_markdown_table(lines, "## Writeback contract")
    return {
        "object_id": identity.get("Object ID", path.stem),
        "memory_type": identity.get("Memory type", "unknown"),
        "owner_scope": identity.get("Owner scope", DEFAULT_OWNER_SCOPE),
        "source": identity.get("Source", "human input"),
        "status": identity.get("Status", "draft"),
        "last_updated": identity.get("Last updated", utc_now()[:10]),
        "content": extract_section(text, "Content", ["Retrieval contract", "Writeback contract", "Governance notes", "Evidence and linked artifacts"]),
        "retrieval_trigger": retrieval.get("Retrieval trigger", "define-me"),
        "retrieval_form": retrieval.get("Retrieval form", "summary"),
        "freshness_rule": retrieval.get("Freshness rule", "define-me"),
        "confidence_threshold": retrieval.get("Confidence threshold", "0.8"),
        "max_retrieval_scope": retrieval.get("Max retrieval scope", "1 object"),
        "writeback_trigger": writeback.get("Writeback trigger", "confirmed durable memory"),
        "human_review_required": writeback.get("Human review required", "yes"),
        "deprecation_rule": writeback.get("Deprecation rule", "replace when superseded"),
        "deletion_path": writeback.get("Deletion path", "delete file and regenerate bundle"),
        "governance_notes": extract_section(text, "Governance notes", ["Evidence and linked artifacts"]),
        "evidence_and_linked_artifacts": extract_section(text, "Evidence and linked artifacts", []),
        "path": str(path.relative_to(WORKSPACE_ROOT)),
    }


def list_memory_objects_data() -> list[dict[str, Any]]:
    MEMORY_DIR.mkdir(parents=True, exist_ok=True)
    return [parse_memory_object(path) for path in sorted(MEMORY_DIR.glob("*.md"))]


def find_memory_path(object_id: str) -> Path | None:
    slug = slugify(object_id)
    direct = MEMORY_DIR / f"{slug}.md"
    if direct.exists():
        return direct
    for path in MEMORY_DIR.glob("*.md"):
        parsed = parse_memory_object(path)
        if parsed["object_id"] == object_id:
            return path
    return None


def build_bundle_manifest() -> dict[str, Any]:
    BUNDLE_DIR.mkdir(parents=True, exist_ok=True)
    memory_objects = list_memory_objects_data()
    manifest = {
        "generated_at": utc_now(),
        "workspace": str(WORKSPACE_ROOT),
        "manifest_summary": load_manifest_summary(),
        "core_files": [
            relative
            for relative in ["context_manifest.yaml", "governance_policy.md", "eval_scorecard.md", "feedback_log.md", "README.md"]
            if (WORKSPACE_ROOT / relative).exists()
        ],
        "memory_objects": [
            {
                "object_id": item["object_id"],
                "memory_type": item["memory_type"],
                "status": item["status"],
                "path": item["path"],
            }
            for item in memory_objects
        ],
        "artifacts": list_relative_files(ARTIFACT_DIR),
        "server_files": list_relative_files(WORKSPACE_ROOT / "mcp_server"),
        "tools_files": list_relative_files(WORKSPACE_ROOT / "tools"),
        "counts": {
            "memory_objects": len(memory_objects),
            "artifacts": len(list_relative_files(ARTIFACT_DIR)),
            "server_files": len(list_relative_files(WORKSPACE_ROOT / "mcp_server")),
            "tools_files": len(list_relative_files(WORKSPACE_ROOT / "tools")),
        },
        "notes": [
            "This manifest is a portability aid, not a full backup format.",
            "Review ownership, redaction, deletion, and access-control constraints before external handoff.",
            "The MCP server files are indexed so the receiving runtime can reconstruct the live BYOC interface as well as the stored context.",
        ],
    }
    write_text(BUNDLE_PATH, json.dumps(manifest, indent=2))
    return manifest


@mcp.tool()
def describe_context_system() -> dict[str, Any]:
    summary = load_manifest_summary()
    memory_objects = list_memory_objects_data()
    artifacts = list_relative_files(ARTIFACT_DIR)
    return {
        "server_name": SERVER_NAME,
        "default_transport": DEFAULT_TRANSPORT,
        "workspace": str(WORKSPACE_ROOT),
        "manifest_summary": summary,
        "counts": {
            "memory_objects": len(memory_objects),
            "artifacts": len(artifacts),
        },
        "bundle_manifest_exists": BUNDLE_PATH.exists(),
    }


@mcp.tool()
def list_memory_objects(memory_type: str = "", status: str = "") -> list[dict[str, Any]]:
    items = list_memory_objects_data()
    if memory_type:
        items = [item for item in items if item["memory_type"] == memory_type]
    if status:
        items = [item for item in items if item["status"] == status]
    return items


@mcp.tool()
def get_memory_object(object_id: str) -> dict[str, Any]:
    path = find_memory_path(object_id)
    if not path:
        return {"error": f"Memory object not found: {object_id}"}
    return parse_memory_object(path)


@mcp.tool()
def upsert_memory_object(
    object_id: str,
    memory_type: str,
    content: str,
    owner_scope: str = DEFAULT_OWNER_SCOPE,
    source: str = "human input",
    status: str = "draft",
    retrieval_trigger: str = "define-me",
    retrieval_form: str = "summary",
    freshness_rule: str = "define-me",
    confidence_threshold: float = 0.8,
    max_retrieval_scope: str = "1 object",
    writeback_trigger: str = "confirmed durable memory",
    human_review_required: bool = True,
    deprecation_rule: str = "replace when superseded",
    deletion_path: str = "delete file and regenerate bundle",
    governance_notes: str = "Document redaction, sharing, ownership, or retention constraints here.",
    evidence_and_linked_artifacts: str = "List supporting files, chats, or outputs here.",
) -> dict[str, Any]:
    if memory_type not in VALID_MEMORY_TYPES:
        return {"error": f"Invalid memory type: {memory_type}"}

    filename = MEMORY_DIR / f"{slugify(object_id)}.md"
    payload = {
        "object_id": object_id,
        "memory_type": memory_type,
        "owner_scope": owner_scope,
        "source": source,
        "status": status,
        "last_updated": utc_now()[:10],
        "content": content.strip(),
        "retrieval_trigger": retrieval_trigger,
        "retrieval_form": retrieval_form,
        "freshness_rule": freshness_rule,
        "confidence_threshold": confidence_threshold,
        "max_retrieval_scope": max_retrieval_scope,
        "writeback_trigger": writeback_trigger,
        "human_review_required": "yes" if human_review_required else "no",
        "deprecation_rule": deprecation_rule,
        "deletion_path": deletion_path,
        "governance_notes": governance_notes.strip(),
        "evidence_and_linked_artifacts": evidence_and_linked_artifacts.strip(),
    }
    write_text(filename, render_memory_object(payload))
    return parse_memory_object(filename)


@mcp.tool()
def delete_memory_object(object_id: str, permanent: bool = False) -> dict[str, Any]:
    path = find_memory_path(object_id)
    if not path:
        return {"error": f"Memory object not found: {object_id}"}

    if permanent:
        path.unlink()
        return {"deleted": object_id, "mode": "permanent"}

    payload = parse_memory_object(path)
    payload["status"] = "deleted"
    payload["last_updated"] = utc_now()[:10]
    payload["governance_notes"] = (payload.get("governance_notes") or "") + "\\n\\nTombstoned by delete_memory_object."
    write_text(path, render_memory_object(payload))
    return {"deleted": object_id, "mode": "tombstone", "path": str(path.relative_to(WORKSPACE_ROOT))}


@mcp.tool()
def list_artifacts() -> list[dict[str, Any]]:
    ARTIFACT_DIR.mkdir(parents=True, exist_ok=True)
    return [
        {
            "path": str(path.relative_to(WORKSPACE_ROOT)),
            "size_bytes": path.stat().st_size,
        }
        for path in sorted(ARTIFACT_DIR.rglob("*"))
        if path.is_file()
    ]


@mcp.tool()
def build_portable_bundle() -> dict[str, Any]:
    return build_bundle_manifest()


@mcp.tool()
def append_feedback_log(category: str, observation: str, planned_fix: str = "") -> dict[str, Any]:
    FEEDBACK_LOG_PATH.parent.mkdir(parents=True, exist_ok=True)
    if not FEEDBACK_LOG_PATH.exists():
        write_text(
            FEEDBACK_LOG_PATH,
            "# Context Feedback Log\\n\\n| Timestamp (UTC) | Category | Observation | Planned fix |\\n|---|---|---|---|",
        )
    with FEEDBACK_LOG_PATH.open("a", encoding="utf-8") as handle:
        safe_observation = observation.replace("|", "/")
        safe_fix = planned_fix.replace("|", "/")
        safe_category = category.replace("|", "/")
        handle.write(f"| {utc_now()} | {safe_category} | {safe_observation} | {safe_fix} |\\n")
    return {"logged": True, "category": category, "feedback_log": str(FEEDBACK_LOG_PATH.relative_to(WORKSPACE_ROOT))}


@mcp.resource("context://manifest")
def manifest_resource() -> str:
    return read_text(MANIFEST_PATH)


@mcp.resource("context://bundle")
def bundle_resource() -> str:
    if not BUNDLE_PATH.exists():
        build_bundle_manifest()
    return read_text(BUNDLE_PATH)


@mcp.resource("context://feedback-log")
def feedback_log_resource() -> str:
    return read_text(FEEDBACK_LOG_PATH)


@mcp.prompt()
def review_memory_writeback(proposed_memory: str, reason: str = "") -> str:
    return f"""Review the following proposed durable memory writeback before it is stored in the user's portable context system. Confirm that it is stable, typed correctly, governance-safe, and worth retaining across future runs. Reason for writeback: {reason or 'not provided'}\\n\\nProposed memory:\\n{proposed_memory}"""


def main() -> None:
    parser = argparse.ArgumentParser(description="Run the generated portable-context MCP server.")
    parser.add_argument("--transport", choices=["stdio", "streamable-http"], default=DEFAULT_TRANSPORT)
    parser.add_argument("--dry-run", action="store_true", help="Validate the workspace and print a summary without starting the server")
    args = parser.parse_args()

    if args.dry_run:
        print(json.dumps(describe_context_system(), indent=2))
        return

    if args.transport == "stdio":
        mcp.run()
        return

    mcp.run(transport="streamable-http")


if __name__ == "__main__":
    main()
'''


def write_text(path: Path, text: str) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(textwrap.dedent(text).rstrip() + "\n", encoding="utf-8")


def write_executable(path: Path, text: str) -> None:
    write_text(path, text)
    path.chmod(0o755)


def main() -> None:
    parser = argparse.ArgumentParser(description="Scaffold a buildable portable context OS workspace.")
    parser.add_argument("output_dir", help="Directory to create or update")
    parser.add_argument("--name", default="portable-context-workspace", help="Context system name")
    parser.add_argument("--ownership", default="personal", choices=["personal", "team", "enterprise"], help="Ownership mode")
    parser.add_argument("--goal", default="portable working context for agents", help="Primary goal")
    parser.add_argument("--source-runtime", default="current-runtime", help="Current runtime or source tool")
    parser.add_argument("--target-runtime", default="target-runtime", help="Target runtime or destination tool")
    parser.add_argument("--server-name", default="", help="Optional MCP server display name; defaults to the context system name")
    parser.add_argument("--transport-default", default="stdio", choices=["stdio", "streamable-http"], help="Default transport for the generated MCP server")
    args = parser.parse_args()

    root = Path(args.output_dir).expanduser().resolve()
    root.mkdir(parents=True, exist_ok=True)

    owner_label = {"personal": "user", "team": "team", "enterprise": "organization"}[args.ownership]
    server_name = args.server_name or args.name

    write_text(root / "README.md", README)
    write_text(
        root / "context_manifest.yaml",
        MANIFEST.format(
            name=args.name,
            ownership=args.ownership,
            goal=args.goal,
            source_runtime=args.source_runtime,
            target_runtime=args.target_runtime,
            owner_label=owner_label,
            transport_default=args.transport_default,
        ),
    )
    write_text(root / "governance_policy.md", GOVERNANCE.format(name=args.name))
    write_text(root / "eval_scorecard.md", SCORECARD.format(name=args.name))
    write_text(root / "feedback_log.md", FEEDBACK_LOG)
    write_text(root / "memory_objects" / "example_preference.md", MEMORY_OBJECT.format(ownership=args.ownership))
    write_text(root / "artifacts" / "artifact_notes.md", "# Artifact Notes\n\nAdd source files, briefs, drafts, reports, or links here.\n")

    tools_dir = root / "tools"
    tools_dir.mkdir(exist_ok=True)
    shutil.copy2(Path(__file__).with_name("build_context_bundle.py"), tools_dir / "build_context_bundle.py")
    (tools_dir / "build_context_bundle.py").chmod(0o755)

    server_dir = root / "mcp_server"
    server_dir.mkdir(exist_ok=True)
    server_code = (
        SERVER_CODE.replace("__SERVER_NAME__", server_name)
        .replace("__DEFAULT_OWNER_SCOPE__", args.ownership)
        .replace("__DEFAULT_TRANSPORT__", args.transport_default)
    )
    write_executable(server_dir / "server.py", server_code)
    write_text(server_dir / "README.md", SERVER_README)
    write_text(server_dir / "requirements.txt", REQUIREMENTS)
    write_text(server_dir / ".env.example", ENV_EXAMPLE)
    write_text(
        server_dir / "client_config.example.json",
        CLIENT_CONFIG.format(
            server_slug=args.name.replace(" ", "-").lower(),
            absolute_server_path=str((server_dir / "server.py").resolve()),
        ),
    )

    write_executable(root / "run_mcp_stdio.sh", STDIO_RUN)
    write_executable(root / "run_mcp_http.sh", HTTP_RUN)

    print(f"Scaffolded portable context workspace at: {root}")
    print("Generated a working MCP server scaffold at ./mcp_server/server.py")
    print("Next steps: edit the manifest and governance files, install dependencies, dry-run the server, then rebuild the bundle manifest.")


if __name__ == "__main__":
    main()
