From ca18e8db08710517ea929dc892111ef42f14d1ad Mon Sep 17 00:00:00 2001 From: demo-bot Date: Mon, 31 Aug 2026 14:48:28 +0000 Subject: [PATCH] decomposer: generate files for Create and commit a registry-ready single-agent repository that generates technical solution design documents and draw.io architecture diagrams from application requirements. --- .../plans/wf-decompose-009b4010a9ea/DETAIL.md | 12 ++ .../plans/wf-decompose-009b4010a9ea/MAP.md | 21 ++++ README.md | 20 ++- application_landing_zone_agent/__init__.py | 5 + application_landing_zone_agent/cli.py | 26 ++++ application_landing_zone_agent/generator.py | 116 ++++++++++++++++++ application_landing_zone_agent/model.py | 42 +++++++ pyproject.toml | 19 +++ tests/test_generator.py | 30 +++++ 9 files changed, 288 insertions(+), 3 deletions(-) create mode 100644 .agents/plans/wf-decompose-009b4010a9ea/DETAIL.md create mode 100644 .agents/plans/wf-decompose-009b4010a9ea/MAP.md create mode 100644 application_landing_zone_agent/__init__.py create mode 100644 application_landing_zone_agent/cli.py create mode 100644 application_landing_zone_agent/generator.py create mode 100644 application_landing_zone_agent/model.py create mode 100644 pyproject.toml create mode 100644 tests/test_generator.py diff --git a/.agents/plans/wf-decompose-009b4010a9ea/DETAIL.md b/.agents/plans/wf-decompose-009b4010a9ea/DETAIL.md new file mode 100644 index 0000000..689189d --- /dev/null +++ b/.agents/plans/wf-decompose-009b4010a9ea/DETAIL.md @@ -0,0 +1,12 @@ +# Plan Detail + +## Step 2: Implement the application_landing_zone_agent in the target repository by adapting the single_agent template to the defined contracts, generating TSD documents and draw.io architecture diagrams, and committing the completed implementation. + +- **Capability:** Create and commit a registry-ready single-agent repository that generates technical solution design documents and draw.io architecture diagrams from application requirements. +- **Plan label:** gap +- **Reusable capability:** True +- **Rationale:** The resulting agent is an independently reusable registry capability that future workflows can discover and invoke. +- **Input schema:** `{'template_repository_url': 'string', 'target_repository_url': 'string', 'repository_structure': 'object', 'required_files': 'string[]', 'configuration_conventions': 'object', 'interface_conventions': 'object', 'implementation_patterns': 'string[]', 'documentation_conventions': 'string[]', 'diagram_generation_conventions': 'string[]', 'agent_goal': 'string', 'agent_specification': 'object', 'system_prompt': 'string', 'configuration_requirements': 'object'}` +- **Output schema:** `{'target_repository_url': 'string', 'implementation_status': 'string', 'implemented_files': 'string[]', 'agent_entrypoint': 'string', 'configured_capabilities': 'string[]', 'commit_reference': 'string', 'implementation_summary': 'string', 'validation_results': 'object'}` +- **Acceptance criteria:** (none) +- **Success conditions:** (none) diff --git a/.agents/plans/wf-decompose-009b4010a9ea/MAP.md b/.agents/plans/wf-decompose-009b4010a9ea/MAP.md new file mode 100644 index 0000000..c900939 --- /dev/null +++ b/.agents/plans/wf-decompose-009b4010a9ea/MAP.md @@ -0,0 +1,21 @@ +# Plan Map + +**Workflow:** wf-decompose-009b4010a9ea +**Intent:** Build Phase 2 HLD & Design Agent (application_landing_zone_agent) using single_agent template from https://gitea.kyndemo.live/agents/single_agent to generate TSD documents and draw.io architecture diagrams, pushing to https://gitea.kyndemo.live/agents/application_landing_zone_agent +**This repo covers:** step 2 + +## Dependency graph + +- Step 0: no dependencies +- Step 1: depends on step 0 +- Step 2: depends on step 0, step 1 +- Step 3: depends on step 0, step 1, step 2 +- Step 4: depends on step 0, step 1, step 2, step 3 + +## Phase table + +Phase 1: step 0 +Phase 2: step 1 +Phase 3: step 2 +Phase 4: step 3 +Phase 5: step 4 diff --git a/README.md b/README.md index 0b85e23..b7ba208 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,19 @@ -# crucible-agent-create-commit-registry +# application_landing_zone_agent -> Create and commit a registry-ready single-agent repository that generates technical solution design documents and draw.io architecture diagrams from application requirements. +A registry-ready transformation tool that converts application requirements into a technical solution design (TSD) document and an editable draw.io architecture diagram. -A tool, not a standing agent service — see `input.schema.json`/`output.schema.json` for its contract. Generated by crucible-agent-decomposer for a plan gap step; language and structure are whatever the capability actually needs, not a fixed layout. +## Usage + +```bash +python -m application_landing_zone_agent requirements.json --output-dir ./artifacts +``` + +Requirements may be a JSON object or a plain-text file. JSON supports `name`, `summary`, `requirements`, `constraints`, `users`, `integrations`, `security`, `data`, `availability`, and `deployment` fields; unknown fields are preserved in the assumptions section. + +Outputs: + +- `technical-solution-design.md` — structured, reviewable TSD +- `architecture.drawio` — editable draw.io XML with logical architecture, trust boundaries, and data flows +- `manifest.json` — deterministic output metadata + +The tool is deterministic and has no network or cloud-provider dependency. Run tests with `pytest`. diff --git a/application_landing_zone_agent/__init__.py b/application_landing_zone_agent/__init__.py new file mode 100644 index 0000000..d708133 --- /dev/null +++ b/application_landing_zone_agent/__init__.py @@ -0,0 +1,5 @@ +"""Application landing zone design generator.""" + +from .generator import generate + +__all__ = ["generate"] diff --git a/application_landing_zone_agent/cli.py b/application_landing_zone_agent/cli.py new file mode 100644 index 0000000..8e1a92a --- /dev/null +++ b/application_landing_zone_agent/cli.py @@ -0,0 +1,26 @@ +from __future__ import annotations + +import argparse +import json +from pathlib import Path + +from .generator import generate + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser(description="Generate a TSD and editable draw.io architecture diagram") + parser.add_argument("requirements", help="JSON requirements file or plain-text requirements file") + parser.add_argument("--output-dir", default="artifacts") + args = parser.parse_args(argv) + source = Path(args.requirements).read_text(encoding="utf-8") + try: + requirements = json.loads(source) + except json.JSONDecodeError: + requirements = source + result = generate(requirements, args.output_dir) + print(json.dumps(result, indent=2)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/application_landing_zone_agent/generator.py b/application_landing_zone_agent/generator.py new file mode 100644 index 0000000..f87291e --- /dev/null +++ b/application_landing_zone_agent/generator.py @@ -0,0 +1,116 @@ +from __future__ import annotations + +import hashlib +import html +import json +from pathlib import Path +from typing import Any + +from .model import Requirements, normalize + + +def _bullets(items: list[str], empty: str = "To be confirmed") -> str: + return "\n".join(f"- {item}" for item in (items or [empty])) + + +def render_tsd(r: Requirements) -> str: + assumptions = r.extra or {"landing_zone": "A governed network, identity, logging, and security baseline is available."} + assumptions_md = "\n".join(f"- **{k}:** {json.dumps(v, ensure_ascii=False)}" for k, v in assumptions.items()) + return f"""# Technical Solution Design: {r.name} + +## 1. Purpose and scope +{r.summary or 'Define a secure, observable, and scalable application landing zone for the stated requirements.'} + +## 2. Functional requirements +{_bullets(r.requirements)} + +## 3. Actors and integrations +### Users and consuming systems +{_bullets(r.users)} + +### External integrations +{_bullets(r.integrations)} + +## 4. Proposed architecture +The application is deployed into a governed landing zone behind an edge entry point and application boundary. Identity, secrets, encryption, monitoring, audit logging, and policy enforcement are platform capabilities. Data stores remain private and are reached through controlled service paths. See `architecture.drawio` for the editable logical view. + +### Logical components +| Component | Responsibility | Trust zone | +|---|---|---| +| Edge / API entry | TLS termination, routing, rate limiting | Public boundary | +| Application services | Business logic and API processing | Application | +| Identity and secrets | Authentication, authorization, key and secret lifecycle | Security | +| Data services | Durable application state and backups | Data | +| Observability | Metrics, logs, traces, alerting, audit evidence | Operations | + +## 5. Security and compliance +{_bullets(r.security)} + +Baseline controls include least-privilege identities, private data services, encryption in transit and at rest, centralized audit logs, secret rotation, vulnerability management, and separation of deployment roles. + +## 6. Data design +{_bullets(r.data)} + +Data classification, retention, residency, backup frequency, recovery point objective (RPO), and recovery time objective (RTO) must be confirmed before production approval. + +## 7. Availability, resilience, and performance +- **Availability target:** {r.availability} +- **Deployment model:** {r.deployment} +- Use health checks, autoscaling where supported, multi-zone placement for production, tested backups, and defined failure-mode runbooks. + +## 8. Network and deployment topology +Ingress is restricted to the edge boundary. Application-to-data traffic uses private routes and explicit security policies. Administrative access uses a controlled management path; direct public access to workloads and data stores is prohibited. + +## 9. Operations +Define dashboards for golden signals, actionable alerts, centralized logs, deployment rollback, patching ownership, incident response, and periodic access reviews. + +## 10. Risks and decisions +- Confirm workload classification, regulatory obligations, traffic estimates, and non-functional targets. +- Select concrete cloud services and sizing after a platform review; this design intentionally remains provider-neutral. +- Validate integration authentication, data contracts, and failure/retry behavior with each dependency. + +## 11. Assumptions and open items +{assumptions_md} +""" + + +def _cell(cell_id: str, value: str, style: str, x: int, y: int, w: int, h: int, parent: str = "1") -> str: + return f'' + + +def render_drawio(r: Requirements) -> str: + title = html.escape(f"{r.name} - Logical Architecture") + box = "rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=13;" + boundary = "rounded=1;whiteSpace=wrap;html=1;dashed=1;fillColor=#f5f5f5;strokeColor=#666666;verticalAlign=top;align=left;spacingTop=8;" + edge = "rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" + cells = [ + _cell("public", "Public / consumer boundary", boundary, 20, 20, 900, 500), + _cell("application", "Application trust zone", boundary, 260, 100, 420, 330), + _cell("data", "Private data zone", boundary, 710, 100, 180, 330), + _cell("edge", "Edge / API entry", edge, 55, 220, 160, 60), + _cell("identity", "Identity & secrets", box, 300, 135, 170, 60), + _cell("service", "Application services", box, 300, 235, 170, 70), + _cell("observe", "Metrics / logs / audit", box, 300, 345, 170, 60), + _cell("store", "Database / object storage", box, 720, 235, 160, 70), + _cell("admin", "Controlled admin path", box, 55, 345, 160, 60), + '', + '', + '', + '', + ] + return f''' +''' + ''.join(cells) + '''''' + + +def generate(requirements: dict[str, Any] | str, output_dir: str | Path) -> dict[str, Any]: + r = normalize(requirements) + out = Path(output_dir) + out.mkdir(parents=True, exist_ok=True) + tsd = render_tsd(r) + diagram = render_drawio(r) + (out / "technical-solution-design.md").write_text(tsd, encoding="utf-8") + (out / "architecture.drawio").write_text(diagram, encoding="utf-8") + digest = hashlib.sha256((tsd + diagram).encode()).hexdigest() + manifest = {"application": r.name, "artifacts": ["technical-solution-design.md", "architecture.drawio"], "sha256": digest} + (out / "manifest.json").write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8") + return manifest diff --git a/application_landing_zone_agent/model.py b/application_landing_zone_agent/model.py new file mode 100644 index 0000000..71065a2 --- /dev/null +++ b/application_landing_zone_agent/model.py @@ -0,0 +1,42 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Any + + +@dataclass +class Requirements: + name: str = "Application" + summary: str = "" + requirements: list[str] = field(default_factory=list) + constraints: list[str] = field(default_factory=list) + users: list[str] = field(default_factory=list) + integrations: list[str] = field(default_factory=list) + security: list[str] = field(default_factory=list) + data: list[str] = field(default_factory=list) + availability: str = "To be confirmed" + deployment: str = "To be confirmed" + extra: dict[str, Any] = field(default_factory=dict) + + +def _list(value: Any) -> list[str]: + if value is None: + return [] + if isinstance(value, list): + return [str(item) for item in value] + return [str(value)] + + +def normalize(raw: dict[str, Any] | str) -> Requirements: + if isinstance(raw, str): + return Requirements(name="Application", summary=raw, requirements=[raw]) + known = {"name", "summary", "requirements", "constraints", "users", "integrations", "security", "data", "availability", "deployment"} + return Requirements( + name=str(raw.get("name", "Application")), summary=str(raw.get("summary", "")), + requirements=_list(raw.get("requirements")), constraints=_list(raw.get("constraints")), + users=_list(raw.get("users")), integrations=_list(raw.get("integrations")), + security=_list(raw.get("security")), data=_list(raw.get("data")), + availability=str(raw.get("availability", "To be confirmed")), + deployment=str(raw.get("deployment", "To be confirmed")), + extra={str(k): v for k, v in raw.items() if k not in known}, + ) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..d671baa --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,19 @@ +[build-system] +requires = ["setuptools>=68"] +build-backend = "setuptools.build_meta" + +[project] +name = "application-landing-zone-agent" +version = "0.1.0" +description = "Generate TSD documents and editable draw.io architecture diagrams from application requirements" +requires-python = ">=3.10" +dependencies = [] + +[project.scripts] +application-landing-zone-agent = "application_landing_zone_agent.cli:main" + +[tool.pytest.ini_options] +testpaths = ["tests"] + +[tool.setuptools.packages.find] +include = ["application_landing_zone_agent*"] diff --git a/tests/test_generator.py b/tests/test_generator.py new file mode 100644 index 0000000..c596e3b --- /dev/null +++ b/tests/test_generator.py @@ -0,0 +1,30 @@ +import json + +from application_landing_zone_agent.generator import generate, render_drawio, render_tsd +from application_landing_zone_agent.model import normalize + + +def test_normalize_and_tsd_include_contract_sections(): + r = normalize({"name": "Orders", "requirements": ["place orders"], "security": ["SSO"], "custom": "kept"}) + tsd = render_tsd(r) + assert "# Technical Solution Design: Orders" in tsd + assert "Functional requirements" in tsd + assert "SSO" in tsd + assert "custom" in tsd + + +def test_drawio_is_editable_xml_and_escapes_title(): + xml = render_drawio(normalize({"name": "A & B"})) + assert xml.startswith("