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

11 KiB
Raw Blame History

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:

$ 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:

{
  "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:

{
  "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:

fruix service status sshd
fruix service status sshd --json
fruix service explain sshd

Or maybe:

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:

$ 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:

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.

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:

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.

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.

{ "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:

fruix why /frx/store/...-freebsd-bash-5.3.9
fruix why service sshd
fruix why config services.sshd.enable

Answers like:

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:

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:

fruix inspect <object> [name]
fruix explain <object> [name]
fruix search <term>
fruix why <object> [name]
fruix graph <object> [name]

Examples:

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:

fruix service status sshd --format annotated

Output:

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.