3.0 KiB
Design notes
The mechanism
f() wraps a command in a loop with one job: don't fail the same way twice.
- Look up whether this exact command line has a known fix, keyed by the literal string of the command and its arguments.
- If it does,
evalthe fix first (a precondition — create a file, export a variable, start a dependency, whatever the fix needs to do), then run the command itself. - If the command still fails, prompt for a fix, log
command=fixtop, apply it, and retry. - Repeat until the command succeeds or the user gives up (blank input).
The state file p is the entire "memory" of the system. It's line-oriented,
grep-able, diffable, and mergeable — ordinary Unix text, not a database.
Why "autopoietic"
Maturana and Varela coined autopoiesis to describe systems that continuously produce the components that make up the system itself — a living cell doesn't consult an external blueprint; the process of metabolizing is the process that rebuilds the cell's own boundary and machinery.
f() is a deliberately tiny analogy: the artifact it produces (p) is fed
back into how the function behaves on its next invocation. There's no
separation between "the program" and "the program's own history of repairs" —
the history is part of the program's behavior from that point on. It's a
toy, not a claim that a shell function is alive — but the self-referential
loop (behavior → artifact → behavior) is the same shape.
Known limitations
- Fixes are preconditions, not replacements.
f cmdalways re-runscmdverbatim; the learned fix only gets to run before it. If the actual problem is thatcmditself was wrong (a typo, wrong flag), no precondition can save it — you'd loop forever re-typing the same fix. This is intentional: you're teaching the environment to accommodate the command, not rewriting the command. - Keying is exact-string.
f ls fooandf ls foo(two spaces) are different keys. There's no fuzzy matching or parameterization. - No expiry or invalidation. A fix that made sense once (e.g. "install
a package that existed at the time") can go stale, and
fhas no way to know that.pis meant to be reviewed and edited by hand like any other config file. - Shared
pacross unrelated commands is a security surface. Anyone who can write topcan get arbitrary codeeval'd the next time a matching command runs. Treatpwith the same trust level as a shell rc file — don't pull one from an untrusted source and source it blind. - The 41-byte original recurses instead of looping, and re-reads no
per-command key — it only remembers the last fix, for whatever command
most recently failed.
src/f.shfixes both, at the cost of a few more lines.
Where this is used
The hardened version boots inside AdaptiveOS — a minimal Alpine-based live
ISO that drops you into a shell with f() and its p file living on a
tmpfs workspace, so the loop can learn and forget freely within a session.