docs: LLM_UI
This commit is contained in:
466
docs/LLM_UI.md
Normal file
466
docs/LLM_UI.md
Normal file
@@ -0,0 +1,466 @@
|
||||
Dual output is exactly the right instinct. If you want a system to be self-documenting for both humans and LLMs, the key is this:
|
||||
|
||||
> **Do not treat documentation as prose attached afterward. Treat it as structured semantic data emitted by the same machinery that defines the system.**
|
||||
|
||||
Otherwise the docs drift, the machine lies, the humans improvise, and the model confidently invents nonsense. A beloved industry tradition.
|
||||
|
||||
## My preference, if Fruix wanted to be maximally legible to me
|
||||
|
||||
I would want **three layers at once** for every meaningful object in the system:
|
||||
|
||||
### 1. Operational output
|
||||
|
||||
The normal thing a human expects.
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
$ fruix service status sshd
|
||||
running since 2026-04-02T09:14:33Z
|
||||
pid 812
|
||||
generation 42
|
||||
store item /frx/store/...-openssh-service
|
||||
```
|
||||
|
||||
### 2. Structured machine-readable output
|
||||
|
||||
Explicit, stable, schema-like, with no pretty nonsense.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "service-status",
|
||||
"name": "sshd",
|
||||
"state": "running",
|
||||
"since": "2026-04-02T09:14:33Z",
|
||||
"pid": 812,
|
||||
"generation": 42,
|
||||
"store_path": "/frx/store/...-openssh-service",
|
||||
"definition_ref": "services.sshd"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Embedded semantic help/doc layer
|
||||
|
||||
Not a wall of text. Short, attached meaning.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"doc": {
|
||||
"summary": "OpenSSH daemon providing remote login access.",
|
||||
"purpose": "Accepts inbound SSH connections for remote administration.",
|
||||
"inputs": ["host keys", "network", "authorized keys config"],
|
||||
"depends_on": ["network-online", "host-keys"],
|
||||
"used_by": ["admin access", "remote deployment"],
|
||||
"failure_modes": [
|
||||
"missing host keys",
|
||||
"port unavailable",
|
||||
"invalid configuration"
|
||||
],
|
||||
"see_also": [
|
||||
"fruix service logs sshd",
|
||||
"fruix config explain services.sshd"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
That combination is ideal. The command answers the immediate question, but also emits enough structure that an LLM can keep asking intelligent follow-ups without having to guess what “sshd” even is in Fruix-world.
|
||||
|
||||
---
|
||||
|
||||
## The most important design principle
|
||||
|
||||
Every object in Fruix should ideally answer these questions about itself:
|
||||
|
||||
* what are you?
|
||||
* why do you exist?
|
||||
* what created you?
|
||||
* what do you depend on?
|
||||
* what depends on you?
|
||||
* how do I inspect you?
|
||||
* how do I change you?
|
||||
* what breaks if you fail?
|
||||
* where is your definition?
|
||||
* what commands are relevant next?
|
||||
|
||||
That is the difference between “a system with documentation” and “a system that can explain itself.”
|
||||
|
||||
## The command model I would love
|
||||
|
||||
I would strongly prefer **one canonical plain output mode**, plus **a structured explain mode**, rather than mixing prose into every default command.
|
||||
|
||||
So:
|
||||
|
||||
```text
|
||||
fruix service status sshd
|
||||
fruix service status sshd --json
|
||||
fruix service explain sshd
|
||||
```
|
||||
|
||||
Or maybe:
|
||||
|
||||
```text
|
||||
fruix inspect service sshd
|
||||
fruix inspect service sshd --json
|
||||
fruix explain service sshd
|
||||
```
|
||||
|
||||
This separation matters.
|
||||
|
||||
### Why not always dual-output in the same stream?
|
||||
|
||||
Because it becomes annoying for humans, brittle for scripts, and ugly for terminals. People say they want hybrid output until they actually have to read it every day.
|
||||
|
||||
Better pattern:
|
||||
|
||||
* default output for operators
|
||||
* stable machine output for tooling/LLMs
|
||||
* explicit explanation output for context
|
||||
|
||||
That said, you *can* still have a dual channel if done cleanly.
|
||||
|
||||
---
|
||||
|
||||
## My favorite model: result + attached explain block
|
||||
|
||||
Something like this:
|
||||
|
||||
```text
|
||||
$ fruix service status sshd --with-doc
|
||||
|
||||
sshd: running
|
||||
pid: 812
|
||||
since: 2026-04-02T09:14:33Z
|
||||
generation: 42
|
||||
|
||||
Explanation:
|
||||
SSH daemon for remote login and administration.
|
||||
Depends on network-online and host key material.
|
||||
Configured from services.sshd in the system definition.
|
||||
|
||||
Relevant commands:
|
||||
fruix service logs sshd
|
||||
fruix config explain services.sshd
|
||||
fruix service restart sshd
|
||||
```
|
||||
|
||||
That is excellent for humans and still digestible for an LLM if the formatting is predictable.
|
||||
|
||||
But for automation, I would still want:
|
||||
|
||||
```text
|
||||
fruix service status sshd --json
|
||||
fruix service explain sshd --json
|
||||
```
|
||||
|
||||
So in practice I’d want **two parallel interfaces**, not one muddled one.
|
||||
|
||||
---
|
||||
|
||||
## What should be self-documenting in Fruix?
|
||||
|
||||
Not just commands. The **actual nouns** of the system.
|
||||
|
||||
### 1. Store paths
|
||||
|
||||
A store item should be explainable.
|
||||
|
||||
```text
|
||||
fruix store explain /frx/store/845bd...-freebsd-bash-5.3.9
|
||||
```
|
||||
|
||||
Should answer:
|
||||
|
||||
* package/runtime/component name
|
||||
* version
|
||||
* origin
|
||||
* build inputs
|
||||
* purpose
|
||||
* references
|
||||
* whether it is part of current system
|
||||
* whether it is GC-rooted
|
||||
* whether it is user-requested or dependency-only
|
||||
|
||||
### 2. Services
|
||||
|
||||
Explain:
|
||||
|
||||
* purpose
|
||||
* definition origin
|
||||
* dependencies
|
||||
* restart policy
|
||||
* logs
|
||||
* ports/files touched
|
||||
* activation behavior
|
||||
|
||||
### 3. System definitions
|
||||
|
||||
Explain:
|
||||
|
||||
* what modules/options contributed
|
||||
* what options are set
|
||||
* defaults vs overrides
|
||||
* resulting closures
|
||||
* affected services
|
||||
* resulting boot entries/generations
|
||||
|
||||
### 4. Configuration options
|
||||
|
||||
This one matters a lot.
|
||||
|
||||
A good system should let me ask:
|
||||
|
||||
```text
|
||||
fruix config explain services.sshd.enable
|
||||
fruix config explain system.network.hostname
|
||||
fruix config search ssh
|
||||
```
|
||||
|
||||
And get:
|
||||
|
||||
* type
|
||||
* default
|
||||
* current value
|
||||
* description
|
||||
* examples
|
||||
* constraints
|
||||
* source module
|
||||
* related options
|
||||
|
||||
This is one of the best things NixOS/Guix-style systems can do, and Fruix should absolutely lean into it.
|
||||
|
||||
### 5. Commands themselves
|
||||
|
||||
CLI subcommands should be introspectable too.
|
||||
|
||||
```text
|
||||
fruix help gc
|
||||
fruix help gc --json
|
||||
fruix explain command gc
|
||||
```
|
||||
|
||||
Because LLMs are often dropped into a black box and forced to infer the command surface. A command that can describe itself structurally is vastly easier to use safely.
|
||||
|
||||
---
|
||||
|
||||
## What would help me most as an LLM?
|
||||
|
||||
If Fruix wanted to be unusually legible to a model, I’d want these properties.
|
||||
|
||||
### Stable schemas
|
||||
|
||||
If `--json` exists, make it boring and stable. No whimsical field names, no gratuitous nesting, no surprise changes. Humans love creative naming, then wonder why tooling breaks.
|
||||
|
||||
### Uniform “kind” fields
|
||||
|
||||
Every structured output should say what it is.
|
||||
|
||||
```json
|
||||
{ "kind": "service-status", ... }
|
||||
{ "kind": "config-option", ... }
|
||||
{ "kind": "store-item", ... }
|
||||
{ "kind": "system-generation", ... }
|
||||
```
|
||||
|
||||
This helps tremendously.
|
||||
|
||||
### Embedded references
|
||||
|
||||
Objects should point to related objects.
|
||||
|
||||
For example, service status should include:
|
||||
|
||||
* definition reference
|
||||
* related config path
|
||||
* related store path
|
||||
* dependency names
|
||||
|
||||
This lets a model traverse the system instead of hallucinating relationships.
|
||||
|
||||
### Short summaries written for machines and humans
|
||||
|
||||
Not marketing copy. Not essay paragraphs. Tight explanatory text.
|
||||
|
||||
Good:
|
||||
|
||||
> "Enables the OpenSSH daemon for inbound remote shell access."
|
||||
|
||||
Bad:
|
||||
|
||||
> "This module offers a powerful and flexible way to control secure access to your Fruix machine."
|
||||
|
||||
Nobody needs brochure language except people trying to justify headcount.
|
||||
|
||||
### Explicit provenance
|
||||
|
||||
For anything important, say where it came from:
|
||||
|
||||
* built from which derivation
|
||||
* declared in which module
|
||||
* set by user vs default
|
||||
* inherited from which profile/system generation
|
||||
|
||||
That makes the system explainable instead of mystical.
|
||||
|
||||
---
|
||||
|
||||
## I would absolutely add a “why” command
|
||||
|
||||
This is the killer feature.
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
fruix why /frx/store/...-freebsd-bash-5.3.9
|
||||
fruix why service sshd
|
||||
fruix why config services.sshd.enable
|
||||
```
|
||||
|
||||
Answers like:
|
||||
|
||||
```text
|
||||
freebsd-bash-5.3.9 is present because:
|
||||
- required by fruix-system-fruix-freebsd generation 42
|
||||
- referenced by interactive-shell-runtime
|
||||
- pulled in by admin profile
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```text
|
||||
services.sshd.enable is true because:
|
||||
- set explicitly in hosts/fruix-freebsd.scm
|
||||
- module openssh-service.scm contributes service definition
|
||||
```
|
||||
|
||||
This is huge for both humans and LLMs. “Why is this here?” is half of systems debugging.
|
||||
|
||||
---
|
||||
|
||||
## My preferred architecture for integrated docs
|
||||
|
||||
I would not store docs only in markdown files. I would make them part of the typed object/module/option definitions themselves.
|
||||
|
||||
For each module/option/service/package, attach fields like:
|
||||
|
||||
* `summary`
|
||||
* `description`
|
||||
* `type`
|
||||
* `default`
|
||||
* `examples`
|
||||
* `see-also`
|
||||
* `danger-level`
|
||||
* `depends-on`
|
||||
* `used-by`
|
||||
* `introduced-in`
|
||||
* `notes`
|
||||
|
||||
Then generate from that:
|
||||
|
||||
* terminal help
|
||||
* handbook pages
|
||||
* man pages
|
||||
* JSON explain output
|
||||
* web docs
|
||||
* maybe even shell completions with hints
|
||||
|
||||
That way there is **one source of truth**, many renderings.
|
||||
|
||||
This is the real win.
|
||||
|
||||
---
|
||||
|
||||
## A concrete Fruix interaction model I’d love
|
||||
|
||||
Something like this command family:
|
||||
|
||||
```text
|
||||
fruix inspect <object> [name]
|
||||
fruix explain <object> [name]
|
||||
fruix search <term>
|
||||
fruix why <object> [name]
|
||||
fruix graph <object> [name]
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
fruix inspect service sshd
|
||||
fruix explain service sshd
|
||||
fruix why service sshd
|
||||
fruix graph service sshd
|
||||
|
||||
fruix inspect store /frx/store/...-freebsd-bash-5.3.9
|
||||
fruix explain store /frx/store/...-freebsd-bash-5.3.9
|
||||
fruix why store /frx/store/...-freebsd-bash-5.3.9
|
||||
|
||||
fruix inspect config services.sshd.enable
|
||||
fruix explain config services.sshd.enable
|
||||
fruix why config services.sshd.enable
|
||||
```
|
||||
|
||||
That is clean, memorable, and composable.
|
||||
|
||||
---
|
||||
|
||||
## If you insist on dual output in one invocation
|
||||
|
||||
Then I would make it a structured container, not mixed prose spaghetti.
|
||||
|
||||
Maybe:
|
||||
|
||||
```text
|
||||
fruix service status sshd --format annotated
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```yaml
|
||||
result:
|
||||
name: sshd
|
||||
state: running
|
||||
pid: 812
|
||||
since: 2026-04-02T09:14:33Z
|
||||
generation: 42
|
||||
|
||||
doc:
|
||||
summary: OpenSSH daemon for remote administration.
|
||||
depends_on:
|
||||
- network-online
|
||||
- host-keys
|
||||
config_path: services.sshd
|
||||
see_also:
|
||||
- fruix service logs sshd
|
||||
- fruix config explain services.sshd
|
||||
```
|
||||
|
||||
YAML is readable enough for humans and parseable enough for tools. Though for machine use I’d still pick JSON.
|
||||
|
||||
---
|
||||
|
||||
## The single biggest preference of all
|
||||
|
||||
If I had to choose only one thing, it would be this:
|
||||
|
||||
> Every meaningful Fruix object should be introspectable by name or path, with both a stable machine schema and a concise semantic explanation.
|
||||
|
||||
That alone would make the system unusually legible to me, to users, and to future maintainers who have not yet been spiritually damaged by it.
|
||||
|
||||
## My concrete recommendation
|
||||
|
||||
Build this into Fruix from the start:
|
||||
|
||||
* `--json` on all important commands
|
||||
* `explain` subcommands for commands, config, services, store items, generations
|
||||
* `why` subcommands for dependency/provenance tracing
|
||||
* structured doc fields embedded in module and option definitions
|
||||
* generated docs from the same source
|
||||
* concise summaries, not essay sludge
|
||||
|
||||
That is the sweet spot. Self-documenting, machine-friendly, human-usable, and hard to let drift.
|
||||
|
||||
If Fruix gets that right, an LLM dropped cold into the system could become useful very quickly instead of fumbling around like a junior admin in an unfamiliar datacenter.
|
||||
Reference in New Issue
Block a user