Skip to content
Sign in

Concept

How Zof understands your system

Updated

On this page

Zof judges a change by the services it touches: how critical they are, who owns them, and how they're tagged. Part of that it finds in your code. The rest only a person can say, and Zof takes it from your system map. Nothing in a map applies until a company admin accepts it.

What the code shows, and what only a person can say

The System Graph reads each repository's default branch. From your manifests and code it finds the services, the datastores and many of the links between them: which service calls, reads, writes or depends on which.

Some facts aren't in the code:

FactWhy it matters
TierHow critical a service is. Rules apply by tier, and an unknown tier counts as tier 0, the strictest.
OwnerWho is asked to approve a change to it when a rule needs owners' approval, and who can take over an agent's change. With no owner known, nobody can take over.
DomainsNames that group services. Zof's decisions don't use them.
TagsLabels such as payments that rules match on. Unknown tags never count as "no tags": a rule that matches on a tag still applies.

A person says these in the system map, a zof.yaml file. Every key is in System map fields.

Is zof.yaml required?

No, zof.yaml is optional. Without it, the System Graph still finds your services, datastores and the links between them from the repository's docker-compose files, Kubernetes manifests in kubernetes-manifests/, app manifests such as package.json or pyproject.toml, and the environment variables your code reads.

You need a map for what those files can't say: each service's tier, owner, domains, tags and environments, and links the code doesn't show, such as calls to a service in another repository. Without a map these stay unknown, which is why a map is important: Zof never treats unknown as safe. Rules treat a service with no tier as tier 0, the strictest, and its risk shows as Unknown, never Low.

Zof reads zof.yaml from the default branch only. An admin can keep the map in Zof instead of committing a file: see Set it in the console instead. With no map yet, click Review map on Home and Zof drafts one for you to review: see Set up your system map.

Where the map in use comes from

For each repository, the System Graph uses the first of these that exists:

  • a stored copy: a map a company admin accepted in the Zof console, kept by the System Graph, which keeps every version;
  • the repository's own zof.yaml, on its default branch;
  • a file Zof's team keeps for the repository, in rare cases. The System map row's badge then still reads "Not mapped", because Zof checks only the repository's own zof.yaml;
  • nothing: every tier is unknown, so the strictest, and every tag is unknown.

A stored copy wins over the repository's own file. While one is in use, the graph ignores the repository's zof.yaml, and changes to that file don't apply. That's why putting a stored copy in use needs its own tick, and why Stop using the stored copy exists: it makes the repository's file apply again.

The map is read from the default branch only, never from a pull request. Otherwise a pull request could lower its own service's tier. See Change zof.yaml safely.

How a draft is made

A draft starts from what the graph found and from the map in use. Values already set are carried forward unchanged. The links the graph found are shown for reference but aren't written into the file: a written link would outlive the code that made it.

When you generate a draft, AI can suggest four things for the services the graph found: tier, owner, domains and tags. It never adds a service, a link, an endpoint or an agent. By default it only fills values that are empty. A person can ask it to suggest changes to set values too, on that one draft.

Zof checks each suggestion before it reaches the draft. It needs a reason and one to five files the model actually read. A suggested owner must appear, word for word, in one of those files. Values must fit the field. A suggestion that fails is dropped and listed, and the field keeps its earlier value. The owner check only stops the model inventing a name. It's no sign of trust: a file in the repository can name anyone, so every owner change needs a tick.

What the AI reads and sends

AI drafting is enabled by default for every company, including existing companies and new GitHub connections. Click Review map on Home to open or generate a draft, then review and edit it. No separate activation is needed. The Review tab labels the result as AI suggestions, partial suggestions or a basic draft. Generating does not commit a file to GitHub, and nothing applies until an admin accepts the draft for storage in the System Graph.

For each AI draft Zof gives the model:

  • the services the System Graph found, with their folders, links, environment variable names (not values), dependencies and models;
  • the values already set, when you ask it to suggest changes to them;
  • the repository's file listing, and the text of files the model asks for, at the commit the graph read.

Zof reads the repository with a read-only GitHub token for that one repository. Per draft, the model reads at most 40 files, 32 KB of each and 400 KB in all, in at most 18 turns and 40 tool calls, with about two minutes for the model. Nothing it has can write anything or reach another site.

It never gets secret-looking files: .env files (except .env.example), keys and certificates, SSH keys, credentials files, .npmrc, .pypirc, .netrc and .htpasswd files, Kubernetes and Docker logins, Terraform state and variables, and any path containing secret. Binary files are refused too. Before any text is sent, Zof replaces anything shaped like a cloud key, an access token, a private key or a password value.

The model runs in Zof's Azure tenant. Zof keeps which files were read, with their size and a fingerprint (hash) of what was sent, and the checked suggestions. It doesn't keep the file text or the rest of the model's answer.

A repository with more than 200 services, or too many files to list, gets no AI. If drafting stops early, Zof may retain suggestions already checked against files it read; the review labels those suggestions as partial and asks you to inspect their reasons and citations. Otherwise a failed or unreadable run leaves the draft without AI suggestions. Zof never treats a partial draft as a completed AI review.

Why AI can't change a result

Zof decides about a change from the map in use, your release policy, the evidence and the approvals, with fixed code. A suggestion is only text in a draft until a person reviews it and an admin accepts it. The AI's reasons show as plain text, and its worst case is a wrong value that a person then accepts. That's why the changes that make Zof less strict need a tick. See How Zof decides.

Why nothing applies until an admin accepts

Accepting a map changes how strictly Zof judges every later change. So it takes a company admin in Zof who is also an admin of your GitHub account, checked with GitHub each time. Zof records the version with that person's GitHub ID, verified email and the time.

Every change that makes Zof less strict, or moves authority, must be acknowledged: a higher tier number, a removed tag, link or service, tags set where they were unknown, any owner, path, endpoint or agent change, and putting a stored copy in use. An owner can approve changes and take over an agent's change, so a new owner is new authority. Draft review groups explained changes behind one informed confirmation, while special or unfamiliar changes retain individual checkboxes. The list is in Changes that lower protection.

After an admin accepts, the version is stored, then applied when the System Graph next reads the repository. Until then it shows as "applying", never as in use.

When the structure changes

Zof watches for new services and links. Within about an hour of the System Graph reading a new commit on the default branch, Zof compares the services and links it found with the ones the latest draft here was built on. Environment variables, files and confidence don't count, so routine edits aren't a structure change.

If they changed, Zof makes a new draft by itself, at most one a day per repository. It waits when a draft is open with the same structure, when a draft is being made, or when the copy in use was confirmed under a previous connection. A repository with no draft here yet gets no structure drafts.

Every Monday at 06:00 UTC a weekly check drafts any repository whose structure moved since its latest draft, even if a structure draft was made in the last 24 hours, and any repository with no map at all that has never had a draft here. Structure and weekly drafts only fill empty values, use AI only when it's on, and never apply on their own.

History is kept per company

Drafts, acceptances and versions belong to your company, and nothing in them is deleted. The History tab lists your company's drafts and the stored versions your company made, plus the one in use.

A GitHub account can end its connection with one company and connect to another. The new company never sees the drafts or history the old one made. The System Graph keeps the stored copy per repository, so one confirmed before can still be in use. It then shows as "Confirmed vN under a previous connection", and Zof makes no draft for that repository until an admin adopts or stops it. AI drafting remains enabled by default on the new connection.

Explore the topology workspace

Open Topology to see the services and relationships recorded by the System Graph. One line under the title says how fresh the map is: Map updated and when, or Map updated: Not reported when the graph sent no read time, which is unknown, not fresh. One button beside it is the next step for the state you're in:

  • Pick a change lists the latest 50 changes across the organization, so an empty list does not mean a repository has no change history. Released to narrows that list to the changes released to an environment, for example production. It doesn't narrow the map. The environments come from the release outcomes the control plane records; until a listed change has one, it is off.
  • Refresh shows when the System Graph says a repository is out of date, with its reason. It reads the map and its map changes again. It doesn't make the System Graph read your repositories.
  • Open in Releases shows while a change is open. If you came from a pull request, Back to PR above the title goes to the same place instead.
  • Show the latest shows on a past version of the map.

Map version and Export are always under the three dots, and so is Refresh, except while it is the one button beside the title. Map version shows the graph as it was at an earlier revision. The System Graph numbers each read of your repositories 1, 2, 3… and never reuses a number. The line under the title then says you are looking at a past revision and when it is from. If the graph has no such revision or didn't record history that far back, the workspace says so instead of showing today's graph. Export downloads the graph.

Filter holds Repository and Service, and each one in use shows as a chip you can remove. Repository focuses on one repository, and related services from other repositories stay visible as context. If no repository is chosen here, the project selected in the header decides. Service focuses on one service.

Choose Graph, Map or Table to switch views. Topology opens on Graph. When Graph would open too small to read on your screen, below about 50% zoom, it opens on Map instead. A view with more than 200 entities opens as a table so the page stays usable, and says so; choose a repository or service to narrow it, or Graph to draw them all. The view you choose, or a link's ?view=, always wins. On Graph, services with no links are set out in a grid, inside their repository's box when there is one. The table shows 100 rows at a time, with a button to show more. Each row gives the service's tier, its repository, its owners, its risk, and how many services it Depends on and how many it is Used by.

Map draws the services to explore: scroll or pinch to zoom, drag to move, and hover a service to see its repository, its tier and how many services it Depends on and is Used by. A filled circle is tier 1, a dashed one has no tier, a square is a datastore, and the number inside is the tier. With a change open, only what it changed is filled, with a ring around it, and what it reached is plain. A small dot marks what changed lately. On a phone, only tier 1 services and those lit by a change carry a name.

Graph draws each service as a card, with each repository's services together in a labelled box; drag a service or a box's header to arrange them, and Reset layout puts them back. Each link has an arrow pointing to what the service depends on.

Key says what the marks mean, including Changed and Reached while a change is lit on the drawing. Untick a kind of link or node to take it off the drawing. Under Risk, High or critical lights the services at that level, from the level the System Graph gives each from its tier: what a change touching only that service would score, not the risk of its open changes. A solid line is a link that is declared in zof.yaml or certain, a dashed line is one a rule worked out, such as from an env var, and a dotted line is one whose source isn't known.

Beside the drawing, Map changes lists the services, datastores and connections added to, removed from or changed on your map since the date it names, usually a week ago, most important first: Removed, Critical service (tier 0 or 1), Tier unknown (a service with no tier, never treated as lower) and Routine. Select a service in the list to choose it. A removed service, a connection, or a service outside the repository or service you chose is listed but can't be selected, and the last says not in this view. Show on Graph or Show on Map, named for the view it uses, lights what changed. None shows only when Zof read every change. When the list is cut short it says At least and how many it shows. When Zof doesn't keep earlier versions of your map it says Not reported, and after its first read it says Not enough data yet. When the read fails it says Temporarily unavailable with Retry, and the map keeps working. When your session has expired or you don't have access, it says so, with no Retry. It describes today's map, so it isn't shown on a past revision or on a map as assessed at its recorded revision. When a push's revision isn't recorded, the page shows today's map, and Map changes with it.

Under it, Gaps counts the services and datastores with no tier, no owner or no environments declared, and its heading says what it counts. Choose one to light them on the view it names, and follow How to declare these in zof.yaml to fill them in. On Home, the System map tile says how many services changed and how many services and datastores have gaps, and each opens this map with them lit.

Pick a change, or follow a pull request's link, and the map lights what it changed and reached and dims the rest. On Graph, a changed service has a red border, a reached one an amber border with how many hops away it is. On a phone, the view opens on the changed service. Beside it are the change risk, its blast radius, any reported risk signals, its environments, its owners, and what it changed and reached. When the graph can't establish the full impact, a line above the map says Impact is not fully mapped whatever you select, the blast radius reads At least, and the section beside the map says why, for example files no service owns, more services past the depth limit, or each entity with no tier in zof.yaml, named with its kind, and dimmed services may still be affected: zero marked services is not proof of zero impact. In the table, the changed and reached services are listed first, with Show on Graph or Show on Map to switch to whichever view draws them readably. Lighting a Gaps row from the table goes to the same view. Remove the change's chip to go back to the whole map.

A pull request's link shows the impact of the push it names; a push the System Graph hasn't analyzed yet says so instead of showing a map. Opened as assessed, the map and impact are shown as they were when that push was assessed, with the date and graph revision and a link to View on today's map; when the graph didn't record that revision, today's map is shown and the page says so. Back to PR returns to the pull request.

Select a service and the panel beside the map shows its key facts: a word from Releases, then its repository, tier, owners, risk, environments, and how many services it depends on and is used by. Anything the graph doesn't know says so. Zof decides per pull request, not per service, so the word always names its change. With a change open it is that change's word, for example Blocked · PR #412 in payments. Otherwise it is the newest open change in the service's repository, for example Blocked · latest change in payments, PR #412. A datastore's word is its repository's in the same way. A new pull request nothing has evaluated yet counts as the newest. No open change in payments means Zof read every open change and none is in that repository; Latest change in payments: Not reported means it couldn't tell. On a past or assessed map there is no repository word, because Releases only knows today, and an open change's word says today. Services it has no link to fade. Click empty space or Map overview to clear it.

Open details opens the service in depth. Close it with Esc, the X, or by clicking outside it.

  • Overview has the latest change and why it stands where it does, whether the open change touches this service (the change risk, the files that changed it, or the path and confidence by which it is reached), and the service's GitHub team, the repository's default branch and last read, and the map revision.
  • Dependencies lists what it Depends on and what it is Depended on by, and each link says how it is known, for example "CALLS · Observed (DECLARED) · 90% confidence". Choose one to move to it.
  • Risks says how the level is set, why it is what it is, and whether the map is stale, with a link to recent changes by risk on Risk. A service with no tier, or whose repository map is stale, is Unknown (except tier 0, which stays Critical), never Low.
  • History lists the earlier changes in its repository from the latest 50, with the word for one still open or, for one that closed, Last decision: and its word, or Not decided yet when it closed before Zof decided. Choose one to open it on the map. With a change open, it also holds that change in depth.

View runs opens Runs filtered to the service's repository. A service with no relationships recorded only means none are in this graph snapshot; it does not prove the code has no dependencies.

Review a draft with its evidence

Repository cards lead to the next map action. The review separates the applied map from the draft result, and explains partial or failed AI work using the recorded outcome. Recorded AI usage and source details are available in a disclosure; indexed paths are not a count of files read.

Review one service at a time with search and previous/next navigation. Before/proposed values, reasons, pinned file citations and protection implications appear beside the fields. For environments, pick one already known to your company or type any other name; it is written to your map. A supported previous value can be restored through the existing editor; any edit requires checking and confirming the changes again. YAML and the full diff remain under Advanced: YAML and full diff. The editor follows the console theme.

History refreshes when an accepted version is opened and when returning to the list. An accessible version stays visible even if the list refresh fails or is delayed. A version being accepted still does not prove it is in use; confirmation remains a separate reported state.

Next steps