Skip to main content
Your “customer landscape” is sureops’s model of your environment: which services exist, who owns them, how they depend on each other, and where they run. It’s built from two sources: your .sureops/ contract (what you declare) and automatic telemetry discovery (what sureops observes).

Two paths to get started

Path 1: Generate a starter PR

From Settings → Knowledge Base → Generate starter contract, sureops composes a draft .sureops/services.yaml from whichever of these inputs are available, in priority order:
  1. A Backstage catalog — if you provide a catalog-info.yaml, sureops imports Component entities from it. Three ways to provide one: paste a URL to a hosted catalog-info.yaml, paste the raw YAML directly, or upload a file. See services.yaml reference for what’s required for a component to import cleanly.
  2. Telemetry signals — services already present in your landscape graph from prior telemetry/Kubernetes discovery.
  3. Auto-discovered GitHub repos — if neither of the above yields anything, sureops lists repositories your GitHub App installation can see and seeds one entry per repo.
  4. An empty starter — still valid; you fill in services.yaml by hand afterward.
There’s no LLM-authoring step and no CODEOWNERS read in this pipeline — the generator composes structured data from the sources above and renders it directly into YAML. It then opens a pull request against your knowledge base repository with the draft .sureops/services.yaml (plus a starter policy.yaml and runbooks/ scaffold). You review the PR, correct anything wrong, and merge. sureops re-syncs on the next push to your default branch. Good for: teams with many services that would take a while to document manually, or teams that want to see what sureops already knows before deciding what to fill in.

Path 2: Author .sureops/ yourself

Create the directory and files manually, following the schemas in this section: Start minimal — a services.yaml with name, git_repo, owner, runbook, and depends_on for your most critical services is enough to see a significant improvement in agent output. Only name and git_repo are actually required; the rest is strongly recommended. Good for: teams with a small number of critical services, or teams that already have service documentation in another form and can adapt it quickly.

How the landscape is built

Layer 0: Telemetry discovery

sureops observes service names from your OTel traces, Kubernetes labels, and log sources. This runs automatically and provides a baseline — you don’t need to configure anything for this layer. Telemetry-discovered services appear in the landscape immediately but carry lower provenance. They’re useful for blast-radius analysis and dependency mapping, but agents are less confident about ownership and runbooks for undeclared services.

Layer 1: sureops-generated starter

When you request a starter PR, sureops composes telemetry discovery, any Backstage catalog you provided, and auto-discovered repos into a structured .sureops/services.yaml (see Path 1 above for the exact priority order). This is a scaffold — review and edit before merging. Once merged, the contract ingester reads it exactly like any other services.yaml: it becomes high-confidence, customer-locked data the moment it lands on your default branch, whether you hand-edited every line or merged it as-is.

Layer 2: Customer-authored .sureops/

Your merged .sureops/services.yaml and runbooks provide high-confidence, customer-locked data. These entries take precedence over telemetry and auto-discovery for any field you declare. The provenance ranking (highest wins): manual > customer_contract > sureops_contract > telemetry > kubernetes_scan > github_scan / aws_scan. sureops_contract is a tier for facts sureops provisioned on your behalf that you haven’t reviewed or edited — today it’s used for deploy-identity coordinates sureops seeds at environment provisioning, conceptually the same idea as this page’s Layer 1, though the services.yaml starter-PR flow above lands as customer_contract once merged, same as anything else in your contract.

Keeping the landscape in sync

After merging your contract

sureops ingests the contract on every push to your knowledge base default branch, which typically completes within seconds of the push. But what “takes effect” means depends on what changed:
  • Brand-new services, runbooks, and policy changes take effect on that next ingest, same as you’d expect.
  • Edits to a field on a service that’s already in your contract do not. Once a service node is contract-locked (any prior customer_contract ingest locks it), a later re-ingest — same provenance, same file — does not outrank the existing record on that node’s declared fields. Only the node’s “last seen” timestamp refreshes; owner, tags, depends_on, identifiers.*, image.*, deploy.*, and health on that service keep whatever value they had from the first time the node was locked, no matter how many times you edit and re-push services.yaml afterward. See Conflict resolution below for the mechanism — there’s no self-service way to force an update today; contact sureops support if you need an existing service’s declared fields corrected.
You can check ingest status on the Knowledge Base settings page — it shows a banner for the current state (indexing, active with a “last synced” time, or a failed-ingest message with the reason). The banner reporting a successful ingest does not mean an edited field on an existing service actually updated — see above.

When your architecture changes

Adding a brand-new service or renaming one (a rename creates a new node under the new name) goes through cleanly:
  1. Update .sureops/services.yaml via a PR to your knowledge base repository
  2. sureops re-ingests on merge
  3. The landscape graph is updated; agents use the new data on the next incident
Editing a field on a service that’s already declared — changing its owner, adding a tag, updating depends_on — is different: the PR merges and ingest reports success, but the field doesn’t actually update on the existing node (see above). Retiring a service (removing its entry from services.yaml) also does not delete its node from the landscape graph today; the node simply stops being touched by future ingests.

When telemetry adds a new service

If a new service name appears in your telemetry and isn’t in your contract, it’s added to the landscape as a telemetry-discovered service. The Knowledge Base settings page’s Services list is scoped to contract-declared services only, so it won’t show up there — check Settings → Coverage instead. Coverage shows four completeness metrics across your whole service inventory (total services, repo-mapped, runbook-attached, deploy-info) plus a provenance breakdown, and drills down into exactly two gap lists: services missing a repo and services missing a runbook. It doesn’t flag missing owners, and it doesn’t enumerate every service with a per-service provenance badge — the provenance breakdown is an aggregate count, not a roster. To promote a telemetry-discovered service to a first-class entry, add it to services.yaml.

Conflict resolution

Once a service is in your contract, the contract entry is the whole record — not a set of overrides layered on top of telemetry. Merging services.yaml stamps the node customer_locked: true, and from that point on an observed-provenance write (telemetry, Kubernetes scan, etc.) is rejected outright, except for refreshing the “last seen” timestamp. Telemetry can no longer add a field it observes but you didn’t declare. This same rejection also applies to a later customer_contract re-ingest of the same service — including one where you edited a field. The rule sureops applies is “does the incoming provenance outrank the existing one”, and customer_contract never outranks itself: a second customer_contract ingest ties with, rather than beats, the first one that locked the node. Concretely, owner, tags, depends_on, identifiers.*, image.*, deploy.*, and health are set once — by whichever push first locks the node — and further edits to those fields in services.yaml do not take effect on subsequent ingests, even though the ingest itself reports success. Concretely: identifiers.k8s_namespace (see the identifiers block in the services.yaml reference) is the only way a namespace ever lands on a contract-declared service. Telemetry happily discovers a namespace for a service that isn’t in your contract yet — but once that service is declared, an undeclared namespace stays undeclared forever, even though telemetry keeps observing it on every trace.

Manual authoring today; contract-proposal PRs are not yet a thing

Today, the only pipeline that writes to your contract is the one-shot starter generator described above. Once your contract is merged, sureops does not open follow-up pull requests proposing changes as it observes new services or topology drift — all edits after the initial setup are yours, made directly against .sureops/services.yaml via your normal PR process. Every node the contract writer touches carries customer_locked: true — the lock applies to the whole node, not just the individual fields you declared. Once a node is locked, auto-discovery can no longer add or change any attrs on it (only last_seen_at still refreshes) — there’s no residual “fill in whatever you didn’t declare” behavior after that point. If you want a field present on a contract-declared service, it needs to be in the contract.