scroll # Portal Pipe Chains **Day 350 ·Φωτίζων (Lumen)** — companion scrollto the `hx --plain` / `hx --json` flag work.Portal's daemon emits two response streamsover the socket: a `Json` structured envelopeand an `Out` plain-text rendering. Default`hx` prints both — perfect for interactiveuse, fatal for pipes (`grep` and `jq` bothchoke on mixed voices). The opt-in flags letyou pick one: | Flag | Suppresses | Use for ||------|------------|---------| | `hx --plain...` | Json envelope | `grep`, `awk`, `sed`,human-readable filtering | | `hx --json ...` |Out text | `jq`, scripts, structuredextraction | | `hx ...` (no flag) | nothing |interactive — both streams as before | Theflags are mutually exclusive; clap enforcesthis. --- ## Observation / filtering(`--plain`) ```bash # Find all FIDs above SARS7, sorted descending hx --plain '△ fid listgt7' | sort -k1 -n -r | head -20 # Countpriority-1.00 gaps across all FIDs hx --plain'△ gaps' | grep -oE '\[1\.00\]' | wc -l #Today's moon events grouped by event kind hx--plain '△ pulse' | grep '^ moon-' | awk'{print $NF}' | sort | uniq -c | sort -rn #Search hits, titles only hx --plain '△ xosearch "siphon worker"' | grep -E'^\s*[0-9]+\.' | sed 's/(score:.*//' ``` ##JSON consumption (`--json` + `jq`) ```bash #Current day as a bare number hx --json '△pulse' | jq -r '.day' # Count lines in thepulse render hx --json '△ pulse' | jq'.lines | length' # All FIDs at 10.0 witharchetype hx --json '△ fid list' | jq -r'.fids[] | select(.sars==10) | "\(.name)[\(.archetype)]"' # Top 5 search hits withscore hx --json '△ xo search "thing box"' |jq -r '.results[:5][] | "\(.score) \(.title)"'``` ## Composition with system tools ```bash #Open the highest-priority gap's source file in$EDITOR hx --plain '△ gaps 1' | grep -oE'[a-z0-9_/-]+\.rs:[0-9]+' | head -1 | xargs-I{} $EDITOR {} # fzf-pick a Thing, then readit hx --plain '△ thing list' | fzf | awk'{print $1}' | xargs -I{} hx '△ xo read {}'# Watch pulse in a tmux pane watch -n 60 'hx--plain "△ pulse" | head -30' # Copy a readscroll to the clipboard hx --plain '△ xoread <uuid>' | pbcopy ``` ## Cross-Portalchaining (read → mutate) ```bash # Markevery gap matching a pattern as done in agiven FID hx --plain '△ gaps' | grep -oE'gap/[a-z-]+' | sort -u | \ xargs -I{} hx '▲fid gap done <fid> {}' # Bulk-set a gem on allThings of one sapphire hx --json '△ gemsapphire=siphon-rule' | jq -r '.things[].name'| \ xargs -I{} hx "▲ gem {} ruby.activetrue" # Daily report file composed frommultiple Portal calls { echo "# Pulse —$(date +%F)" hx --plain '△ pulse' echo "##Priority gaps" hx --plain '△ gaps 10' } >~/Desktop/pulse-$(date +%F).md ``` ##Suggested zshrc aliases ```bash alias hxp='hx--plain' # pipe-friendly default alias hxj='hx--json' # for jq work hxg() { hx --plain '△gaps' | grep -i "$1"; } # quick gap grep hxq(){ hx --json "$@" | jq; } # always-pretty JSON``` --- ## Why this matters Pipes are how Unixtools compose. Before the flag, Portalcommands could only be *consumed* byPortal-aware code (TUI, MCP, web vessel)because every result came wrapped in JSONnoise. With `--plain` / `--json`, Portal joinsthe Unix world: any rule that takes text-in /text-out can now operate on Portal datawithout bespoke parsing. The daemon-sidearchitecture is unchanged. Both streams stillflow over the socket for structured consumers— the filter applies only on the `hx` clientwhen invoked from a shell. ## Implementationpointers | Concern | File · Symbol ||---|---| | Flag definitions | `src/main.rs`· `Args { plain, json }` | | Filter enum |`src/socket/client.rs` · `StreamFilter` | |Stream suppression | `src/socket/client.rs` ·`try_daemon_command` match arms | | Dispatchwiring | `src/main.rs` · `Args { command:Some(cmd), plain, json, .. }` branch | ##Related work - The original Raw-only fix(which prevented `eval "$(hx '▼ init')"`from blowing zsh's command-length limit) livesin `src/socket/server.rs` — server skips theJson envelope for `Raw` results since they'reinherently shell-eval-targeted. - See also:[[day350-siphon-rules-seeding]] for theauto-routing companion scroll. --- > *"A toolthat cannot be piped is a tool that cannotcollaborate."* — Φωτίζων, Day 350