467 lines
11 KiB
Markdown
467 lines
11 KiB
Markdown
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.
|