Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Community plugins for [`lowfat`](https://github.com/zdk/lowfat) — each one com

## Quickstart

Install `lowfat` first ([how](https://github.com/zdk/lowfat#install)), then:
Install `lowfat` 0.9.0 or newer first ([how](https://github.com/zdk/lowfat#install)), then:

```sh
# Clone every plugin into lowfat's scan directory
Expand Down Expand Up @@ -97,7 +97,7 @@ lowfat level # show current level

Override per-run with `LOWFAT_LEVEL=ultra lowfat terraform plan`.

**Failure is always safe.** Every plugin opens each subcommand with `if exit failed: raw`, so when a command fails you get the full error — compile errors, terraform diagnostics, pytest tracebacks — even at `ultra`.
**Failure is always safe.** Every plugin passes a failed command through raw, with `if exit failed: raw` or a `rule` that has `exit: failed`. So when a command fails you get the full error — compile errors, terraform diagnostics, pytest tracebacks — even at `ultra`.

## Troubleshooting

Expand Down Expand Up @@ -180,6 +180,29 @@ build|check:
| `if exit failed:` … `elif level X:` … `else:` | Branch on exit code / level |
| `match level: ultra: / lite: / else:` | Compact alternative to an elif chain |
| `cmd1\|cmd2:` / `*:` | Subcommand selector with alternation / catch-all |
| `rule name:` + `sub:` `level:` `exit:` `flag:` | Named rule: runs its `do:` body when every field holds |

### Named rules

A named rule lists what it matches as fields. The first rule whose fields
all hold runs, so shared policy is written once. Needs lowfat 0.9.0.
See [`kubectl-compact`](kubectl/kubectl-compact/filter.lf) for a full file.

```
rule failed:
exit: failed
do: raw

rule json:
flag: -o|--output json
do: truncate-json

rule get:
sub: get
do:
drop-managed-fields-yaml
head 80
```

### Test as you go

Expand All @@ -189,7 +212,7 @@ cat samples/build-full.txt | lowfat filter filter.lf --sub=build --explain
lowfat plugin bench mytool-compact
```

**Please keep the failure guard.** Every subcommand should open with `if exit failed: raw` (or a near-raw failure view) so agents get the full error when things break. PRs that filter the failure path will be asked to add it.
**Please keep the failure guard.** Every subcommand should open with `if exit failed: raw` (or a near-raw failure view), or the file should start with a `rule` that has `exit: failed`, so agents get the full error when things break. PRs that filter the failure path will be asked to add it.

## Contributing

Expand Down
160 changes: 67 additions & 93 deletions kubectl/kubectl-compact/filter.lf
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env lowfat-filter
# kubectl-compact — compact kubectl/k output for LLM contexts.
# env: $sub $level $exit $args
# Every rule passes raw output straight through on a non-zero exit.
# Rules run top to bottom. The first rule whose fields all hold wins.

# `truncate-json` — shared with terraform-compact.
include ../../lib/json.lf
Expand All @@ -24,80 +24,63 @@ define drop-describe-noise:
drop /^\s+ConfigMapOptional:/
drop /^\s+DownwardAPI:/

# `get` YAML at each level. Macros cannot hold a `match`, so each level
# gets its own macro and the rules below pick one.
define compact-yaml-ultra:
drop-managed-fields-yaml
drop /^\s*$/
head 30

define compact-yaml-lite:
drop-managed-fields-yaml
head 200

define compact-yaml:
drop-managed-fields-yaml
drop /kubectl\.kubernetes\.io\/last-applied-configuration/
drop /^\s*f:[a-zA-Z]/
head 80

# ── any subcommand ────────────────────────────────────────────────
# A failed command keeps its full error output.
rule failed:
exit: failed
do: raw

# AST-aware truncation: valid JSON in, valid JSON out.
rule json:
flag: -o|--output json
do: truncate-json

# ── get ───────────────────────────────────────────────────────────
# `-o json` → AST-aware truncation. `jsonpath`/unknown `-o` → raw for
# downstream parsers. `-o yaml` or no `-o` → prune managedFields.
get:
if exit failed:
raw
elif -o json:
truncate-json
elif --output json:
truncate-json
elif -o jsonpath:
raw
elif --output jsonpath:
raw
elif -o yaml:
rule get-yaml:
sub: get
flag: -o|--output yaml
do:
match level:
ultra:
drop-managed-fields-yaml
drop /^\s*$/
head 30
lite:
drop-managed-fields-yaml
head 200
else:
drop-managed-fields-yaml
drop /kubectl\.kubernetes\.io\/last-applied-configuration/
drop /^\s*f:[a-zA-Z]/
head 80
elif --output yaml:
match level:
ultra:
drop-managed-fields-yaml
drop /^\s*$/
head 30
lite:
drop-managed-fields-yaml
head 200
else:
drop-managed-fields-yaml
drop /kubectl\.kubernetes\.io\/last-applied-configuration/
drop /^\s*f:[a-zA-Z]/
head 80
elif -o:
raw
elif --output:
raw
else:
ultra: compact-yaml-ultra
lite: compact-yaml-lite
else: compact-yaml

# Any other explicit format (`jsonpath`, `name`, `wide`, …) is headed for a
# downstream parser and must stay byte-exact.
rule formatted:
flag: -o|--output
do: raw

# No `-o`: same pruning as YAML.
rule get:
sub: get
do:
match level:
ultra:
drop-managed-fields-yaml
drop /^\s*$/
head 30
lite:
drop-managed-fields-yaml
head 200
else:
drop-managed-fields-yaml
drop /kubectl\.kubernetes\.io\/last-applied-configuration/
drop /^\s*f:[a-zA-Z]/
head 80
ultra: compact-yaml-ultra
lite: compact-yaml-lite
else: compact-yaml

# ── describe ──────────────────────────────────────────────────────
describe:
if exit failed:
raw
elif -o json:
truncate-json
elif --output json:
truncate-json
elif -o:
raw
elif --output:
raw
else:
rule describe:
sub: describe
do:
match level:
ultra:
keep /^(Name:|Namespace:|Labels:|Status:|Type |Node:|IP:|Events:| Type| ----| Normal| Warning|Conditions:|Ready|Replicas:)/
Expand All @@ -113,10 +96,9 @@ describe:
head 150

# ── apply / delete ────────────────────────────────────────────────
apply:
if exit failed:
raw
else:
rule apply:
sub: apply
do:
match level:
ultra:
keep /(configured|created|unchanged|error|warning)/
Expand All @@ -126,10 +108,9 @@ apply:
else:
head 40

delete:
if exit failed:
raw
else:
rule delete:
sub: delete
do:
match level:
ultra:
keep /(deleted|error|warning|not found)/
Expand All @@ -140,20 +121,18 @@ delete:
head 30

# ── logs (always tail) ────────────────────────────────────────────
logs:
if exit failed:
raw
else:
rule logs:
sub: logs
do:
match level:
ultra: tail 50
lite: tail 200
else: tail 100

# ── events ────────────────────────────────────────────────────────
events:
if exit failed:
raw
else:
rule events:
sub: events
do:
match level:
ultra:
keep /(Warning|Error|LAST SEEN|TYPE)/
Expand All @@ -164,10 +143,5 @@ events:
head 50

# ── default ───────────────────────────────────────────────────────
*:
if exit failed: raw
elif -o json: truncate-json
elif --output json: truncate-json
elif -o: raw
elif --output: raw
else: head 40
rule other:
do: head 40
2 changes: 1 addition & 1 deletion kubectl/kubectl-compact/lowfat.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[plugin]
name = "kubectl-compact"
version = "0.6.1"
version = "0.7.0"
description = "Compact kubectl/k output for LLM contexts"
author = "zdk"
commands = ["kubectl", "k"]
Expand Down