--- name: opengraph-integration description: Integrate with the OpenGraph metadata analysis service. Use this skill whenever the user mentions “opengraph”, OpenGraph Analyzer, opengraph.wayl.one, ogcli, `/api/v1/analyze`, metadata extraction, social preview metadata, or asks to consume, extend, deploy, or troubleshoot this service. It covers the HTTP API, CLI, Python service layer, generated metadata, container image, and Argo deployment workflow. compatibility: Requires HTTP access for the hosted API, or the OpenGraph Analyzer repository and uv for local development. Kubernetes deployment changes use the homelab-argo GitOps repository. --- # OpenGraph integration Use OpenGraph Analyzer as a metadata extraction service. Prefer its JSON API for integrations outside the repository. Use the Python service layer only when the integration is part of the OpenGraph Analyzer source tree. ## Choose an integration path | Need | Use | | --- | --- | | Analyze a URL from another service | `POST https://opengraph.wayl.one/api/v1/analyze` | | Inspect a result from a terminal | `ogcli analyze URL --json` | | Reuse logic inside this repository | `opengraph.service.Analyzer` | | Render the existing interface | Jinja + HTMX web routes | | Deploy a new image | `registry.wayl.one/opengraph:` with the generic Kubernetes chart | Do not assume the JSON contract matches Microlink. OpenGraph Analyzer has its own versioned result shape and preserves repeated metadata values. ## HTTP API Send a JSON object with a valid HTTP or HTTPS URL: ```bash curl -fsS https://opengraph.wayl.one/api/v1/analyze \ -H 'content-type: application/json' \ -d '{"url":"https://example.com/"}' ``` The response contains: ```json { "schema_version": "v1", "page": { "url": "https://example.com/", "final_url": "https://example.com/", "title": "Example Domain", "description": null, "standard_meta": {}, "open_graph": {}, "twitter": {}, "article": {}, "images": [], "links": [], "json_ld": [], "response": {}, "security": {}, "cache": {} }, "issues": [] } ``` Treat `page.open_graph` and `page.twitter` values as arrays. A page can have multiple `og:image` values. Treat `issues` as structured data with `field`, `code`, `message`, and `severity`; do not infer validity from whether a field is present. ### HTTP errors Handle these statuses explicitly: - `400`: invalid or unsafe URL. - `413`: fetched document exceeds the service body limit. - `502`: upstream fetch failure. - `504`: upstream timeout. The fetcher rejects credentials, non-HTTP schemes, private/reserved addresses, and unsafe redirect targets. Do not use the service to fetch internal network addresses. The current extractor analyzes server-rendered HTML. It does not execute page JavaScript or provide browser rendering. ## CLI Run the CLI from an installed checkout: ```bash uv sync uv run ogcli analyze https://example.com uv run ogcli analyze https://example.com --json ``` The default output is concise human-readable status. `--json` returns the same versioned analysis result used by the service layer. ## Python service layer Inside the repository, inject a `Fetcher` or `Extractor` when testing or when providing another transport: ```python from opengraph.service import Analyzer result = Analyzer().analyze("https://example.com/") payload = result.to_dict() ``` Core responsibilities are separated into fetching, extraction, validation, and orchestration. Keep FastAPI, Jinja, CLI formatting, and other presentation logic out of the core services. When importing the web application locally, avoid the root `opengraph.py` module/package name collision. Use the package entrypoint and its source path: ```bash uv run uvicorn opengraph.web:app --app-dir src ``` ## Generated metadata When generating `` elements: - Use `property` for `og:*` and `article:*` properties. - Use `name` for standard metadata and `twitter:*` tags. - Escape attribute names and values as HTML. - Preserve multiple Open Graph image entries. - Include `` separately; it is not a `meta` element. Do not silently replace invalid values with empty strings. Return validation issues so callers can show or log the reason. ## Container and deployment The application image used by the existing Argo application is: ```text registry.wayl.one/opengraph:<version> ``` The repository also publishes an analyzer-named image, but the existing `homelab-argo` application uses the `opengraph` image name. Keep those names aligned when updating deployments. Build and test locally with the repository recipes: ```bash just check TAG=0.3.1 just release ``` The release recipe builds with Podman, uses a registry-backed cache, and pushes the image. Docker users can use `just docker-release` with Buildx. For Kubernetes deployment, update only the image tag in: ```text homelab-argo/argo-apps/apps/opengraph.yaml ``` The existing deployment uses: - Argo Application: `opengraph` in namespace `argocd`. - Workload namespace: `opengraph`. - Service port: `8000`. - Public host: `opengraph.wayl.one`. - Generic chart: `https://github.com/waylonwalker/k8s-basic`, path `helm-chart`. Use the normal GitOps flow: commit and push the desired-state change, refresh the parent `1-apps` Application if reconciliation is delayed, then verify: ```bash kubectl get application opengraph -n argocd kubectl -n opengraph rollout status deployment/opengraph --timeout=180s kubectl -n opengraph get deployment opengraph \ -o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}' curl -fsS https://opengraph.wayl.one/health ``` Do not manually apply a competing Deployment when Argo manages this Application. Preserve unrelated local changes in `homelab-argo`. ## Integration report When completing an integration task, report: 1. Integration path and endpoint or package used. 2. API/schema version or image tag. 3. Validation and error handling added. 4. Commands and smoke tests run. 5. Deployment or GitOps status, if changed.