−
100%
+
fit
scroll
# Portal Pipe Chains **Day 350 ·
Φωτίζων (Lumen)** — companion scroll
to the `hx --plain` / `hx --json` flag work.
Portal's daemon emits two response streams
over the socket: a `Json` structured envelope
and an `Out` plain-text rendering. Default
`hx` prints both — perfect for interactive
use, fatal for pipes (`grep` and `jq` both
choke on mixed voices). The opt-in flags let
you pick one: | Flag | Suppresses | Use for |
|------|------------|---------| | `hx --plain
...` | Json envelope | `grep`, `awk`, `sed`,
human-readable filtering | | `hx --json ...` |
Out text | `jq`, scripts, structured
extraction | | `hx ...` (no flag) | nothing |
interactive — both streams as before | The
flags are mutually exclusive; clap enforces
this. --- ## Observation / filtering
(`--plain`) ```bash # Find all FIDs above SARS
7, sorted descending hx --plain '△ fid list
gt7' | sort -k1 -n -r | head -20 # Count
priority-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 '△ xo
search "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 the
pulse render hx --json '△ pulse' | jq
'.lines | length' # All FIDs at 10.0 with
archetype hx --json '△ fid list' | jq -r
'.fids[] | select(.sars==10) | "\(.name)
[\(.archetype)]"' # Top 5 search hits with
score 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 read
it 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 read
scroll to the clipboard hx --plain '△ xo
read <uuid>' | pbcopy ``` ## Cross-Portal
chaining (read → mutate) ```bash # Mark
every gap matching a pattern as done in a
given FID hx --plain '△ gaps' | grep -oE
'gap/[a-z-]+' | sort -u | \ xargs -I{} hx '▲
fid gap done <fid> {}' # Bulk-set a gem on all
Things of one sapphire hx --json '△ gem
sapphire=siphon-rule' | jq -r '.things[].name'
| \ xargs -I{} hx "▲ gem {} ruby.active
true" # Daily report file composed from
multiple 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 Unix
tools compose. Before the flag, Portal
commands could only be *consumed* by
Portal-aware code (TUI, MCP, web vessel)
because every result came wrapped in JSON
noise. With `--plain` / `--json`, Portal joins
the Unix world: any rule that takes text-in /
text-out can now operate on Portal data
without bespoke parsing. The daemon-side
architecture is unchanged. Both streams still
flow over the socket for structured consumers
— the filter applies only on the `hx` client
when invoked from a shell. ## Implementation
pointers | 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 | | Dispatch
wiring | `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) lives
in `src/socket/server.rs` — server skips the
Json envelope for `Raw` results since they're
inherently shell-eval-targeted. - See also:
[[day350-siphon-rules-seeding]] for the
auto-routing companion scroll. --- > *"A tool
that cannot be piped is a tool that cannot
collaborate."* — Φωτίζων, Day 350
△