Files
fruix/docs/LLM_UI.md
2026-04-02 10:25:56 +02:00

467 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 Id 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, Id 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 Id 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 Id 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.