Skip to content

The Model

A server has state. The operator needs to see it, select something within it, and act on it.

That is the invariant. Every REPL design decision follows from it.

The operator is not browsing a menu. They are doing one of three things at any moment:

  1. Getting the landscape — what exists on this server in this domain?
  2. Getting the detail — what is the state of this specific thing right now?
  3. Acting — given what this thing actually is right now, what can I do?

These are three distinct cognitive moments. A REPL that collapses them forces the operator to carry the missing moment in their head. That is where mistakes happen.


The operator enters a module. They see the ambient state of that module’s knowledge domain — all nginx domains, all fail2ban jails, all services. Read live, rendered in one pass. The full landscape, immediately.

The survey answers: what exists? and what is its state?

It is always read from the authoritative source directly. nginx survey reads the nginx config tree. fail2ban survey reads fail2ban-client. The operator sees what is real, not what was real the last time something updated a record.

The survey is not just a stepping stone to focus. It is a diagnostic tool in its own right.

The operator can filter and search within the survey to slice the landscape — by state, by attribute, by any field the module exposes. This is how operators answer questions about the server without drilling into any individual subject:

  • How many domains are currently suspended?
  • Which domains have SSL certificates expiring this week?
  • Is this server issue affecting all domains or only a subset?
  • How many fail2ban jails are active vs inactive?

The filtered survey is itself the answer. The operator may never enter focus at all — they came to understand the landscape, not to act on a specific subject. Filtering within the survey is not a convenience feature. It is the primary way an operator makes sense of a server under investigation.

When the landscape is large, filtering is also how the operator identifies the subject they want before entering focus — narrow by partial name, by status, by any visible attribute until the subject is found, then select it.

The operator selects a subject from the survey. They enter the focus view — everything this module knows about that one subject, read live at the moment of selection.

The focus answers: what is this, right now?

Domain: client-a.com. SSL: expired 3 days ago. Status: suspended. Not “last known status.” Not “status as of last heartbeat.” The state of that domain at this moment, read directly.

At the bottom of the focus view, the operator sees available actions. Not a fixed list of everything this module can do. The actions that apply to this subject given its current live state.

The action answers: what can I do, given what this actually is?

If the domain is suspended, unsuspend is present. suspend is absent — not greyed out, not disabled, absent. Showing suspend on a suspended domain would be a lie about what is possible. The action list is computed from live state every time the operator enters focus.


A fixed action list is a representation of capability — what the module can do in general. That is not what the operator needs. The operator needs to know what they can do right now given the state of this specific subject.

Greyed-out actions are a half-measure. They show the action but signal it is not available. The operator still has to read and dismiss them. They carry cognitive load without carrying information. An action that does not apply is not information — it is noise.

Absent means impossible right now. The operator sees only what is real.


Why Each Module Surveys Its Own Domain Only

Section titled “Why Each Module Surveys Its Own Domain Only”

nginx knows nginx. Cloudflare knows Cloudflare. The nginx survey shows nginx domains. The Cloudflare survey shows Cloudflare DNS records. They are separate surveys, navigated independently.

A merged survey that shows nginx domains with Cloudflare proxy status inline seems convenient. It is not honest. nginx does not know Cloudflare state. Cloudflare does not know nginx state. A view that combines them requires trust in the combining logic — that the data was fetched at the same moment, that the join is correct, that a failure in one does not silently corrupt the other.

Two honest surveys are cleaner than one blended view that is honest about neither source. The operator navigates between them. The navigation is the price of honesty — and it is a small price.


Why Survey Is Ambient and Focus Is Selected

Section titled “Why Survey Is Ambient and Focus Is Selected”

The operator does not always know what they are looking for. Survey gives them the landscape without requiring a search term. They see all domains. One of them looks wrong. They select it.

Focus is the answer to a specific question: tell me everything about this one thing. That is a different cognitive mode from surveying the landscape. The REPL treats them differently because they are different.

If focus were the entry point, the operator would need to name the subject before seeing it. That works when you already know what you want. It fails when you are troubleshooting and the survey is how you find out what is wrong.


Every surface module has the same shape from the outside:

enter module → survey (landscape, read live)
filter/search → slice the landscape — answer questions, identify subjects
select subject → focus (detail, read live)
available actions → computed from focus result
take action → survey refreshes

The operator learns this shape once. Every module follows it. nginx, odoo, fail2ban, system — same shape, different knowledge domain. The familiarity is the point.

The operator may exit after the filter step without ever entering focus. That is a complete and valid use of the REPL — the survey answered the question.


A module’s knowledge domain is sometimes more than one subject type — and sometimes those subjects have hierarchical relationships. The model holds in both cases without growing new primitives.

Multi-surface. A module may declare more than one surface, each scoped to its own subject type. fail2ban knows both jails and bans — two distinct landscapes inside one knowledge domain, each with its own survey and focus. The operator sees them as sibling rows on the home page; the survey-focus-act loop is unchanged inside each.

Drills. A surface may have child surfaces that exist only in the context of a selected parent row. An odoo database row drills into the modules and users of that database — a child survey, scoped to the parent. The relationship is structural (a database always has modules), so it is declared by the module, not computed per row. Each drill level is still a survey: same shape, same three moments, narrower in scope.

In both cases the operator’s mental model is the same loop applied at the right granularity. Multi-surface fans out across subject types; drills nest down through subject relationships; survey-focus-act is the engine at every level.


Not a menu system. Menus list options. Survey shows live state. The distinction matters — the operator is reading reality, not navigating a feature list.

Not a static list. The survey is filterable and searchable. The operator slices the landscape by any visible attribute. A survey of 200 domains filtered to those with expired SSL is a live diagnostic result, not a pre-built report.

Not a dashboard. A dashboard aggregates across domains. Survey is a single module’s honest view of its own domain. Aggregation is the job of aggregator modules, built explicitly for that purpose, not a property of every survey.

Not a command-line with autocomplete. The operator does not type capability names. They navigate to the subject and the available actions surface from its state. The vocabulary is emergent from reality, not memorised from a reference.


survey-focus-act is the model a surface declares: what exists in this domain, what a single subject looks like, and what can be done to it. The REPL is the face that renders this model as a navigable screen — survey as a live table, focus as a detail overlay, act as an action footer. A surface module declares the model; the face provides the interaction.