WRKLOG-2026-06-17

Summary

Wednesday. Fill summary at end of day.

URGENT - All Domains

Carryover Backlog (CRITICAL)

Task Details Origin Days Status

MSCHAPv2 Migration Report

Report due. 6-sheet Standard Report (exec summary, trend, waves, device detail, stale, policy match). Sheet 6 added 05-14: policy match by protocol for removal planning + anonymous identity validation. Migration window 2026-05-04 to 2026-05-30. ~6,227 devices, 5 waves.

2026-04-17

83

P0 - DUE — run report this week

Abnormal Security — ✅ COMPLETE

CR-2026-05-07-abnormal-read-write. CAB approved 2026-05-12. Implemented successfully 2026-05-13. Read/write enabled for pilot group. Post-deployment validation pending.

2026-05-07

63

✅ IMPLEMENTED — post-validation pending

SIEM QRadar → Sentinel Migration

Lead role. Monad console error RESOLVED 2026-05-12 — secrets configured in CHLA production tenant. ISE secure syslog integration in progress — cert imported, remote logging target configured, streaming errors under investigation. Blocking: DCR not created (Rule ID + Stream Name). Azure private network policy unresolved. Victor + Mauricio action.

2026-04-10

90

P0 - ACTIVE — ISE syslog + DCR blocking

Monad Pipeline Evaluation

Sentinel output connector. Console error resolved. 3 of 6 values configured. Remaining: Endpoint URL (have it), Rule ID + Stream Name (need DCR). ISE Remote Logging Target configured 2026-05-18 — TLS cert imported, secure syslog target created. Streaming errors in Monad console under investigation.

2026-03-11

120

P0 - ACTIVE — ISE integration in progress

Guest Redirect ACL

Guest redirect ACL work needed. Related to Mandiant remediation findings.

2026-05-12

58

P0 - TODO

ISE Patch 10 (CVE-2026-20147 CVSS 9.9)

ISE 3.2 Patch 10. Supersedes Patch 9. 61 days on a CVSS 9.9 — schedule maintenance window. Write CR if needed.

2026-03-12

119

P0 - OVERDUE — schedule immediately

k3s NAT verification

NAT rule 170 for 10.42.0.0/16 pod network - test internet connectivity. 64 days — test this week or defer to Q3.

2026-03-09

122

P0 - BLOCKING — TRIAGE: schedule or defer

Wazuh indexer recovery

Restart pod after NAT confirmed working - SIEM visibility blocked. Blocked by k3s NAT — cannot proceed until above resolved.

2026-03-09

122

P0 - Blocked by k3s

Strongline Gateway VLAN fix

8 devices in wrong identity group (David Rukiza assigned)

2026-03-16

115

P0 - TODO

TCP Clocks deployment

ISE identity group validation, query outputs, comms with team. Active d001 data Apr 22-23.

2026-04-22

78

P0 - ACTIVE

IoT Dr. Kim — recurring

Sleep study devices (Apr 15-16), watches recurrence (Apr 22). 5 incident versions in d001. Validate iPSK enrollment.

2026-04-15

85

P0 - RECURRING

Murus Portae (WAF) — Phase 0

FMC cert expired, ACP returns zero rules. d001: zone map, architecture D2, FMC API reference, ops script.

2026-04-16

84

P0 - INVESTIGATING

Vocera EAP-TLS Supplicant Fix

~10 phones failing 802.1X, missing supplicant config. 61 days — schedule with clinical engineering team.

2026-03-12

119

P1 - TODO — schedule

ISE MnT Messaging Service

Enable "Use ISE Messaging Service for UDP syslogs delivery". 61 days — low risk, schedule with ISE Patch 10 maintenance window.

2026-03-12

119

P2 - BUNDLE with Patch 10

Professional backlog remains critical. Check Days column for priorities.

BLOCKERS — Fix Immediately

Task Details Origin Days Impact

Z Fold 7 Termux

gopass and SSH not working

2026-03-10

58

BLOCKER — Cannot access passwords on mobile

gopass v3 organization

Inconsistent structure, poor key-value usage

2026-03-20

48

Inefficient password management, no aggregation

Git history scrub — sensitive personal terms

Plaintext references to personal legal matters in committed worklogs (WRKLOG-2026-03-14, WRKLOG-2026-04-18). Forward-fixed but old commits still contain strings. Requires git filter-repo + force-push. See runbook below.

2026-04-22

15

SECURITY — sensitive terms in public git history

Runbook: Git History Scrub (d000 Personal Terms)

Problem: Two committed worklogs contained plaintext references to personal legal matters. The files have been edited (forward-fix), but git history retains the original text in prior commits.

Affected commits: Any commit touching these files:

# Identify affected commits
git log --oneline -- \
  docs/modules/ROOT/pages/2026/03/WRKLOG-2026-03-14.adoc \
  docs/modules/ROOT/pages/2026/04/WRKLOG-2026-04-18.adoc

Scrub procedure:

# 1. BEFORE: Full backup of the repo
cp -a ~/atelier/_bibliotheca/domus-captures ~/atelier/_bibliotheca/domus-captures.bak

# 2. Install git-filter-repo (if not present)
# Arch: pacman -S git-filter-repo
# pip: pip install git-filter-repo

# 3. Create expressions file for replacement
cat > /tmp/scrub-expressions.txt << 'EXPR'
regex:(?i)divorce==[REDACTED]
regex:(?i)dissolutio(?!n\.adoc\.age)==[REDACTED-LEGAL]
regex:(?i)iliana==[REDACTED-NAME]
regex:(?i)angulo-arreola==[REDACTED-NAME]
regex:legal-divorce-notes\.age==legal-notes.age
regex:1099-NEC-iliana==1099-NEC
EXPR

# 4. Verify before (dry run — count matches in history)
git log -p --all -S 'divorce' -- '*.adoc' | grep -c 'divorce' || echo "0 matches"
git log -p --all -S 'iliana' -- '*.adoc' | grep -c 'iliana' || echo "0 matches"

# 5. Run filter-repo (DESTRUCTIVE — rewrites all commit hashes)
git filter-repo --replace-text /tmp/scrub-expressions.txt --force

# 6. Verify after
git log -p --all -S 'divorce' -- '*.adoc' | grep -c 'divorce' || echo "0 matches — CLEAN"
git log -p --all -S 'iliana' -- '*.adoc' | grep -c 'iliana' || echo "0 matches — CLEAN"

# 7. Re-add remotes (filter-repo removes them)
git remote add origin git@github.com:<user>/domus-captures.git
# Add any other remotes (Gitea, etc.)

# 8. Force-push to all remotes (DESTRUCTIVE — overwrites remote history)
git remote | xargs -I{} git push {} main --force

# 9. Clean up
rm /tmp/scrub-expressions.txt
rm -rf ~/atelier/_bibliotheca/domus-captures.bak  # only after verifying

Post-scrub checklist:

  • Backup created before running

  • git filter-repo installed

  • Expressions file reviewed — no false positives (e.g., Don Quijote "Angulo el Malo" is in segunda-parte/texto/texto-011.adoc — the regex targets angulo-arreola specifically to avoid this)

  • Dry-run counts match expectations

  • Filter-repo executed

  • Post-scrub verification shows 0 matches

  • Remotes re-added

  • Force-pushed to all remotes

  • Cloudflare Pages rebuild verified

  • Local clones on other machines re-cloned or git fetch --all && git reset --hard origin/main

  • Backup removed

URGENT - Requires Immediate Action

Item Details Deadline Status Impact

Housing Search

Granada Hills area - apartments/rooms

TBD

In Progress

Quality of life, commute

2025 Tax — IRS Transcript Review

MFJ filed 2026-04-22. Pull IRS Return Transcript to verify contents. Consult attorney re: Form 8857 (Innocent Spouse Relief). Details in encrypted case file.

Before attorney meeting

In Progress

Financial — liability exposure. See encrypted D000 case file.

Rack Relocation

Physical move of server rack. CR written: CR-2026-04-18 (pending in infra-ops). Borg backup completed. VM XML dumps, switch save, shutdown/startup procedure documented.

TBD

Pending

Infrastructure downtime — all services offline during move

D000 Legal Planning

Encrypted D000 case file. Open: d000 open dissolutio. Close: d000 close dissolutio. 19 partials + assembler. PDF build for attorney handoff. Critical deadline: Jan 2029.

Before Jan 2029

Active — escalating

Life transition — see case file for details

Credit Report Review

Pull reports from all 3 bureaus via annualcreditreport.com. Verify no unknown joint accounts or debts. Credentials in gopass: v3/personal/finance/credit/annual_credit_report

TBD

In Progress

Financial discovery — FL-142 preparation

Gopass Security Audit

Rotate passwords on shared/known accounts. Add 2FA backup codes to v3/personal/recovery/. Create missing government entries (IRS, SSA, VA, DMV). Add last_login field to active entries.

TBD

Pending

Digital security — pre-filing preparation

Subscription Audit

Download 3 months bank/CC statements (Chase, NFCU, USAA). Identify all recurring charges. Cancel unnecessary. Document active subscriptions for FL-150.

TBD

Pending

Financial — expense documentation

401(k) Enrollment

Enroll in CHLA 401(k) immediately. Post-separation contributions are 100% separate property. Reduces gross income for support calculations. Max 2026: $23,500/yr.

In progress (started 5/4)

In Progress

Financial — support calculation + retirement

URGENT — Performance Review Certifications

Certification Provider Deadline Status Impact

CISSP

ISC² — Certified Information Systems Security Professional

July 12, 2026

ACTIVE — Week 2 of 10 (Project)

Required for performance review. 10-week accelerated plan.

RHCSA 9

Red Hat Certified System Administrator

Q3 2026

ACTIVE — 21-phase curriculum (Project)

After CISSP. Required for performance review.

CISSP: 41 days remaining (exam July 12). Domain 1 study in progress. Schedule exam today (06-01).

Early Morning - 5:30am

Regex Training (CRITICAL CARRYOVER)

  • Session 3 - Character classes, word boundaries

  • Practice drills from regex-mastery curriculum

  • Status: 52 days carried over (since 2026-03-16) — CRITICAL

Regex training continues to slip. This is the foundation for all CLI mastery.

Daily Notes

Triage Status

Item Status Destination

Quijote chapters 37-43 — 21 missing attributes fixed

done

atributos-quijote.adoc — all 21 gaps filled, validated in browser

P16g dual-screen + deep-sleep regression

pending

dots-quantum hyprland.conf — investigate kernel/DRM regression

d001 acme-cert — next steps after POC

active

d001 open acme-cert

d001 siem-qradar-to-sentinel — ISE syslog + DCR

blocked

d001 open siem-qradar-to-sentinel

d001 tcp-clocks — onsite testing continues

active

d001 open tcp-clocks

find/glob/regex skill improvement

in progress

codex + daily notes — build on 06-16 cli-search-patterns

Annual review — submit to Sarah (CISO) TODAY

urgent — DUE TODAY

d000 cursus/annual-review — finalize + submit

Linux research document — DUE

urgent

d001 linux-research — finalize deliverable

CISSP — update annual review goal: scheduling Aug 2026

action

Update goal-carryover.tex — not attained, rescheduling

ISE cert expiry (was 06-16 urgent)

verify scope

Check if cert renewed

d001 workflow redesign — 3 data loss incidents

needs design

Atomic workflow — carry forward

Monad blockers (5 people)

blocked

Awaiting others

Carry Forward

Carry Forward from 06-16

Item Status Notes

ISE cert expiry (was 06-16 urgent)

verify scope

Did the cert renew? Check ISE admin UI or openssl s_client

d001 workflow redesign — 3 data loss incidents on 06-15

needs design

Atomic open→edit→build→verify→close→commit workflow

Monad blockers: Kenneth, Mauricio, Victor, Argam, Tony

blocked

Awaiting others — no action unless they respond

ISE rotation (kvm-01) — phases 0-2 done

carry forward

Next: restore/patch/certs

Vault SSH cert timer — not yet built

carry forward

systemd timer needed (8h validity)

VPN SSL cert expiring 2026-07-28

tracking

~41 days remaining

ISE RabbitMQ PID limit at 310%

carry forward

Health warning from 06-10

Urgent

Annual Review — Submit to Sarah TODAY

Review period: CY2025 + H1 2026. Reports to: Sarah Clizer, Manager, Information Security.

Status
  • LaTeX portfolio artifact exists: data/d000/cursus/annual-review/chla/2025/main.tex

  • 37 projects across 5 domains, 14 critical

  • 6 domain partials complete (auth-access, vuln-compliance, network-infra, siem-monitoring, platform-cloud, doc-tooling)

  • Goal carryover section complete — 5/5 goals addressed

  • Summary section complete

  • ✅ Self-eval draft complete: data/d000/cursus/annual-review/chla/2025/self-eval-draft-2026.adoc

  • ✅ All sections drafted with evidence from d001 project notes

  • ✅ 4 CRs documented (VLAN, Abnormal, Guest ACL, Anonymous Identity)

  • ✅ Monad correctly framed as POC — Cribl and Microsoft-native under evaluation

  • ✅ CISSP framed as rescheduled (August 2026) due to operational load

Action items
  • Review all 6 domain partials for accuracy against current project states

  • Draft self-eval with evidence from d001 projects (SIEM, Abnormal, MSCHAPv2, Mandiant, CRs, incidents)

  • Update CISSP goal line: "Scheduling exam ~Aug 2026" — communicate to Sarah that CISSP not yet attained, rescheduling

  • Final read-through of self-eval — adjust voice/tone

  • Copy self-eval sections into xlsx

  • Rebuild PDF: cd data/d000/cursus/annual-review/chla/2025 && pdflatex main.tex && pdflatex main.tex

  • Review output PDF

  • Submit to Sarah

Self-eval rating strategy
  • Exemplary: Job Skills, Outcomes, Growth/Innovation (3 of 8)

  • Effective: Service Excellence + all 4 remaining values (5 of 8)

  • Last year: self-rated all Effective; Sarah upgraded 3 to Exemplary

  • This year: self-rating Exemplary on same 3 — evidence is stronger, backed by numbers

Key numbers (receipts)
  • 1,219 log sources inventoried, 437 types, 55% error rate

  • 6,088 devices across 9 platforms (MSCHAPv2)

  • 20 syslog transforms (POC), 23 SQL queries

  • 30 M365 transport rules audited, 2 high-severity findings

  • 7 Mandiant findings, 4 CRs through CAB, 20+ investigations

  • Cost analysis: $9.9K/yr → $3.9K/yr (ETL pipeline)

CISSP study commitment (starting 2026-06-17)
  • 0530 wake — Domain reading (Sybex, 30-45 min)

  • Evening — 25 practice questions + wrong-answer review (45-60 min)

  • Priority order: Domain 1 → 8 → 6 → 2 → 3 → 4 → 5 → 7

  • Schedule exam this week for mid-August

Linux research document
  • d001 project: d001 open linux-research

  • Deliverable needed for review — enterprise Linux research deployment

Quijote Chapters 37-43 — AsciiDoc Syntax Fixes

URGENT. Chapters 37-43 notas files have broken syntax: undefined attributes (\{c1 loc}, {antitesis}), instead of proper AsciiDoc highlighting (text or text). Needs full audit and repair.

Scope:

  • data/d000/education/quijote-study/notas/p1-cap-037/ through p1-cap-043/

  • Each *-notas.adoc file — check for undefined attributes and broken formatting

  • Cross-reference with custom roles defined in build toolchain (STD-024)

Root cause:

  • 21 attributes used in chapters 37-43 but never defined in atributos-quijote.adoc

  • Three categories: accented variants (7), new rhetorical figures (12), missing domain tags (3)

  • All 21 added to atributos-quijote.adoc — verified zero gaps remain

Validation:

# Open existing builds (from repo root)
for cap in {037..043}; do
  firefox "data/d000/education/quijote-study/notas/p1-cap-${cap}/output/texto-anotado.html" &
done

Rebuild with light-cyan (batch):

# d000 build uses fzf — not scriptable in loops.
# Call build-adoc.sh directly with deterministic paths.
_BUILD=~/atelier/_bibliotheca/domus-asciidoc-build/bin/build-adoc.sh
_BASE=~/atelier/_bibliotheca/domus-captures/data/d000

for cap in {037..043}; do
  echo "=== p1-cap-${cap} ==="
  "$_BUILD" "$_BASE/education/quijote-study/notas/p1-cap-${cap}/texto-anotado.adoc" html --variant light-cyan
done && for cap in {037..043}; do
  firefox "$_BASE/education/quijote-study/notas/p1-cap-${cap}/output/texto-anotado.html" &
done
d000 build wraps build-adoc.sh with interactive fzf file discovery. In loops, call the underlying tool directly — wrappers add value for human selection; scripts need deterministic paths.

Upload to Boox Palma 2 (MTP via simple-mtpfs):

# Mount — Palma 2 must be unlocked + USB connected + "File Transfer" mode
mkdir -p /tmp/palma2
simple-mtpfs /tmp/palma2

# Verify mount
ls /tmp/palma2

# Build PDFs (light-cyan theme)
_BUILD=~/atelier/_bibliotheca/domus-asciidoc-build/bin/build-adoc.sh
_BASE=~/atelier/_bibliotheca/domus-captures/data/d000

for cap in {037..043}; do
  echo "=== PDF: p1-cap-${cap} ==="
  "$_BUILD" "$_BASE/education/quijote-study/notas/p1-cap-${cap}/texto-anotado.adoc" pdf --theme light-cyan
done

# Create target directory on device (if first time)
mkdir -p /tmp/palma2/Books/Quijote

# Copy all PDFs to Palma 2
for cap in {037..043}; do
  local_pdf="$_BASE/education/quijote-study/notas/p1-cap-${cap}/output/texto-anotado.pdf"
  [ -f "$local_pdf" ] && cp "$local_pdf" "/tmp/palma2/Books/Quijote/cap-${cap}-texto-anotado.pdf" \
    && echo "  ✓ cap-${cap}" \
    || echo "  ✗ cap-${cap} — missing"
done

# Verify
ls /tmp/palma2/Books/Quijote/

# Unmount when done (MUST unmount before unplugging)
fusermount -u /tmp/palma2
MTP is a transfer protocol, not a real filesystem — find -delete and some shell operations don’t work. Copy/mkdir work. For bulk deletes, use the device UI.

Kill background tabs (lsof + command substitution):

# Kill background firefox jobs from THIS shell
kill $(jobs -p)

# Kill by port (when process wasn't launched from this shell)
kill $(lsof -t -i :8080)

# lsof key flags:
#   +D dir    — recurse into directory (open files underneath)
#   -c name   — filter by command name
#   -t        — terse: PIDs only (pipeable to kill)
#   -i :port  — filter by network port

Session Work

P16g — Post-Update Regression (3 Symptoms, 1 Root Cause)

Carry forward from 06-16 screen lock fix. All symptoms appeared after the same 2-3 system updates. All were non-existent at project start (clean Razer→P16g migration).

Symptom 1: Dual screen not working
  • External monitor detection broken — was functional at project start

  • Regression window: last 2-3 system updates (kernel/Hyprland/mesa?)

Symptom 2: Deep sleep requires external monitor to wake
  • After deep sleep, laptop screen stays black — no hyprlock prompt

  • Connecting external monitor triggers laptop display to wake

  • Occasionally, laptop monitor resumes immediately upon external connection

  • Pattern: intermittent but reproducible over past 2-3 updates

Symptom 3: USB ports randomly stop working
  • USB ports become unresponsive — any port, random timing

  • Only fix: reboot (not suspend/resume — full reboot)

  • Blocks: MTP device access (Palma 2), USB peripherals

  • Same regression window as symptoms 1 and 2

Common thread

All three symptoms point to power management / PCI-e link state regression:

  • Display (eDP + DP), USB (xHCI), and sleep (S3/s2idle) all traverse PCI-e

  • Arrow Lake-S (P16g Gen 2) has known i915/Xe DRM + Thunderbolt/USB4 power state issues

  • Kernel 7.0.x series introduced changes to PCI-e ASPM and USB autosuspend

Investigation plan
# 1. Identify the regression window — what changed?
# Kernel upgrades
awk '/upgraded linux/{print}' /var/log/pacman.log | tail -10

# All upgrades in the regression window (last 3 updates)
awk '/upgraded/{print}' /var/log/pacman.log | tail -30

# Current kernel
uname -r

# 2. USB diagnostics
lsusb -t                            # USB tree topology
dmesg | grep -i 'xhci\|usb.*error\|usb.*reset\|usb.*disconnect'
cat /sys/bus/usb/devices/*/power/autosuspend_delay_ms   # autosuspend timers

# 3. Display/DRM diagnostics
journalctl -b -g 'drm|i915|xe' --no-pager | tail -30
cat /sys/class/drm/card*/status    # connector states

# 4. PCI-e power management
cat /sys/module/pcie_aspm/parameters/policy
lspci -vv | grep -i 'aspm\|lnkctl'

# 5. Sleep mode
cat /sys/power/mem_sleep            # s2idle vs deep
Root cause identified

Kernel 6.19.14 → 7.0.9 (2026-05-22) introduced the regression. All three symptoms absent on 6.19.x.

Kernel USB Display Sleep Status

6.19.14 (pre May 22)

OK

OK

OK

Worked

7.0.9 (May 22)

Flapping

PHY refclk fail

Black screen

Broke

7.0.11 (Jun 6)

Same

Same

Same

Still broken

6.18.34-lts

Test

Test

Test

Try this

Evidence
  • PHY A failed to request refclk — appears twice at boot (i915 DRM, display C-state clock recovery failure)

  • USB port 3-5 flapping — Palma 2 disconnected after 24s, Samsung phone reconnected 4× in 9 seconds (xHCI controller resetting port)

  • USB autosuspend auto on 11/12 devices — 7.0.x more aggressive power management defaults

  • PCI-e ASPM policy: [default] — defers to BIOS, no explicit Linux override

Fix: Boot LTS kernel (no workarounds)

linux-lts 6.18.34 already installed, boot entry exists, kernel image in /boot.

# Option A — test once: reboot, select "Arch Linux LTS" from systemd-boot menu

# Option B — make LTS default now
# Before
bootctl list | grep -E 'title|default'

# Change
sudo bootctl set-default arch-lts.conf

# After
bootctl list | grep -E 'title|default'

After reboot on LTS:

# Confirm LTS
uname -r

# Verify PHY error gone
journalctl -b -g 'PHY.*failed'

# Test USB — plug in Palma 2, watch for flapping
journalctl -b -f -g 'usb 3-'

# Test sleep — close lid, reopen, check hyprlock appears on laptop screen

Keep linux 7.0.11 installed as fallback. When 7.1 or 7.2 lands with Arrow Lake fixes, switch back and retest.

Post-reboot test (2026-06-17, kernel 7.0.11)

Rebooted on mainline 7.0.11 — all three symptoms persist.

USB flapping — ONYX Palma 2 (MTP)
[720.579576] usb 3-1: New USB device found, idVendor=18d1, idProduct=4ee1
[720.710824] usb 3-1: Product: LAGOON-MTP _SN:2DF6C0DC
[720.710825] usb 3-1: Manufacturer: ONYX
[737.148826] usb 3-1: USB disconnect, device number 12        (1)
[739.085591] usb 3-1: new high-speed USB device number 13     (2)
1 Disconnected after 17 seconds — no user action
2 Reconnected 2 seconds later as new device number — classic xHCI port reset
Why ONYX appears in dmesg but not lsblk

The Palma 2 enumerates as MTP (idVendor=18d1 Google/Android, idProduct=4ee1). MTP is a protocol-level device — it does not create a block device in /dev/sd* or /dev/nvme*. lsblk only shows block devices. To access MTP: gio mount mtp:// or jmtpfs /mnt/palma. The absence from lsblk is normal; the 17-second disconnect is the regression symptom.

LG monitor USB controls — functional
[559.615517] usb 3-5.4: New USB device found, idVendor=043e, idProduct=9a39
[559.615524] usb 3-5.4: Product: USB Controls
[559.615526] usb 3-5.4: Manufacturer: LG Electronics Inc.
[559.631308] cdc_acm 3-5.4:1.1: ttyACM0: USB ACM device

LG monitor DDC/CI controls bound on port 3-5.4 — USB not fully dead, confirming intermittent/selective failure pattern.

Thunderbolt ports — all three bound
[56.004551] typec port0: bound usb4_port1 (ops connector_ops [thunderbolt])
[61.615271] typec port1: bound usb4_port1 (ops connector_ops [thunderbolt])
[67.132976] typec port2: bound usb4_port3 (ops connector_ops [thunderbolt])

TB4 enumeration succeeded — the regression is downstream of the controller, in USB power management.

Next step unchanged: boot LTS kernel 6.18.34 and retest all three symptoms.

  • INC-2026-05-23-002 — same Arrow Lake-S DRM issue family

  • 06-16 lid switch fix — brightnessctl workaround pending

  • P16g deploy project — appendix-issues.adoc candidate

d001 Projects — Active Today

Project Command Focus

ACME Cert Automation

d001 open acme-cert

POC complete — next: move d001→d000, AppRole, Cloudflare into Vault

SIEM QRadar → Sentinel

d001 open siem-qradar-to-sentinel

ISE syslog + DCR blocking — Victor + Mauricio action items

TCP Clocks

d001 open tcp-clocks

Onsite testing continues — new switch RADIUS/AAA config

find — Glob vs Regex Patterns

Yesterday covered find vs rg vs fzf tool selection. Today: mastering find pattern syntax — the glob/regex distinction that caused errors.

The error and why
# BROKEN — | is regex alternation, but -name uses glob
find -name '*03[7,8,9]|04[1,2]*'

# Also wrong — commas inside [] are literal characters
# [7,8,9] matches: 7 , 8 , 9 (five chars, not three)
# [789] matches: 7 8 9 (correct — three chars)
Glob patterns (find -name)

Globs have only three wildcards: * (any chars), ? (one char), […​] (char class). No alternation. No quantifiers. No grouping.

# Character class — correct
find -name '*03[789]*' -type d

# Multiple patterns with -o (OR)
find \( -name '*03[789]*' -o -name '*04[0123]*' \) -type d

# Brace expansion — shell expands BEFORE find sees it
find -name '*p1-cap-0'{37,38,39,40,41,42,43}'*' -type d
# Shell expands to 7 separate -name arguments
Regex patterns (find -regex)

-regex matches the full path, not just the filename. Uses POSIX BRE by default.

# POSIX BRE — escaped grouping and alternation
find -regex '.*p1-cap-0\(3[789]\|4[0-3]\).*' -type d

# Extended regex — cleaner syntax
find -regextype posix-extended -regex '.*p1-cap-0(3[789]|4[0-3]).*' -type d
Key distinction
Feature Glob (-name) Regex (-regex)

Wildcards

*, ?, […​]

., *, +, ?, […​]

Alternation

None (use -o)

| (BRE) or | (ERE)

Scope

Filename only

Full path

Grouping

None

\(\) (BRE) or () (ERE)

Default in find

Yes (-name)

No (must specify -regex)

grep -w: whole-word matching prevents substring traps

Without -w, alternation patterns match substrings — MTP matches SMTP:

# Without -w — 12 false positives from SMTP in ghost-sender investigation
grep -rn 'MTP\|lsblk\|jmtpfs\|gio mount' $(find -name '*daily-notes*' -type d)

# With -w — only whole-word MTP, no SMTP matches
grep -rnw 'MTP\|lsblk\|jmtpfs\|gio mount' $(find -name '*daily-notes*' -type d)

-w wraps each alternation branch in \b…​\b (word boundary). Critical when your search term is a substring of a longer word.

find + grep: two approaches, never nested

Option A — command substitution (fine when paths have no spaces):

grep -rnw 'MTP\|lsblk' $(find -name '*daily-notes*' -type d)

Option B — find -exec (safer, no word-splitting):

find -name '*daily-notes*' -type d -exec grep -rnw 'MTP\|lsblk' {} +

Never nest them. This breaks:

# BROKEN — find -exec grep output becomes arguments to outer grep
grep -rnw 'MTP' $(find -name '*daily-notes*' -type d -exec grep -rn 'MTP' {} +)
# grep output contains "lsblk --scsi" → outer grep parses --scsi as flag → error

The $(…​) substitution feeds stdout as arguments. When grep output contains --flags, the outer grep chokes. These are alternatives, not layers.

sed -n address ranges: extract between patterns

sed -n '/start/,/end/p' prints all lines between two regex matches — useful for extracting content from structured files.

# Extract email body from an AsciiDoc partial (strip markup, keep text)
sed -n '/^Hi \[Medigate/,/^Evan$/p' partials/comms-2026-06-17-medigate-attributes.adoc
  • -n suppresses default output — only p prints

  • /^Hi \[Medigate/ — start pattern (the \[ escapes the bracket — [ is regex special)

  • /^Evan$/ — end pattern ($ anchors to end of line — exact match)

  • Inclusive: both the start and end lines are printed

find | while read: run shell aliases on found files

find -exec spawns a new process — it doesn’t inherit shell aliases. Pipe to while read to stay in your shell:

# BROKEN — build-adoc is an alias, find -exec can't see it
find data/d001/projects/siem-qradar-to-sentinel -maxdepth 1 -name '*.adoc' \
  -exec build-adoc {} html --variant light-cyan \;

# WORKS — while read runs in your shell where aliases live
find data/d001/projects/siem-qradar-to-sentinel -maxdepth 1 -name '*.adoc' | \
  while read -r f; do build-adoc "$f" html --variant light-cyan; done

Three approaches by power level:

# 1. while read — aliases work, sequential
find ... -name '*.adoc' | while read -r f; do build-adoc "$f" html; done

# 2. find -exec with full path — no alias, sequential
find ... -name '*.adoc' -exec ~/path/to/build-adoc.sh {} html \;

# 3. xargs -P for parallel — full path required, NOT bash -ic
find ... -name '*.adoc' -print0 | \
  xargs -0 -P2 -I{} ~/atelier/_bibliotheca/domus-asciidoc-build/bin/build-adoc.sh {} html --variant light-cyan
Never use xargs -P bash -ic — interactive shells (-i) fight over the TTY when run in parallel. Processes suspend with "tty input" error. Use the full path to the script instead.
Showing file content with find: cat vs grep vs sed vs awk

cat does not take -exec — it’s not find. Don’t mix their syntax.

# BROKEN — cat doesn't have -exec
cat $(find -name 'rsyslog-central*.adoc') -exec grep -rn '[source]'

# grep — show lines matching a pattern with context
grep -n -B1 -A2 '\[source' $(find -name 'rsyslog-central*.adoc')

# sed -n — show a specific line range
sed -n '5,38p' $(find -name 'rsyslog-central*.adoc')

# awk — show range between two patterns
awk '/\[source\]/,/^----$/' $(find -name 'rsyslog-central*.adoc')

Three tools, three use cases:

Tool Use case Pattern

grep -n -A -B

Find lines matching a pattern with surrounding context

grep -n -B1 -A5 'pattern' file

sed -n 'X,Yp'

Extract exact line range (when you know the line numbers)

sed -n '5,38p' file

awk '/start/,/end/'

Extract between two patterns (when you know the delimiters)

awk '/\[source\]/,/^----$/' file

$(find …​) works with all three — it expands to the file path. The key: find finds, the other tool processes. Never give cat arguments meant for find.

Practice exercises
  1. Find all Quijote chapters 1-10: find -regex '.*p1-cap-0\(0[1-9]\|10\)' -type d

  2. Find all .adoc files modified in the last 2 days: find -name '*.adoc' -mtime -2 -type f

  3. Find all session files across d001: find data/d001 -name 'session-.adoc' -not -name '.age'

find — Advanced Patterns (Tested Live)

All commands tested on this system. Real output confirmed.

Recency — what changed and when
Most recently modified files (human-readable)
find ~ -type f -printf '%TY-%Tm-%Td %TH:%TM %p\n' | sort -rn | head -20
Files modified in the last N minutes (with size)
find ~ -type f -mmin -30 -printf '%TY-%Tm-%Td %TH:%TM:%TS %12s %p\n' | sort -rn | head -15
Files modified today — scoped to a project, excluding .git
find ~/atelier/_bibliotheca/domus-captures -type f -newermt "2026-06-17" \
  ! -path '*/.git/*' -printf '%TH:%TM  %p\n' | sort -rn | head -20

-newermt takes a date string — compares mtime against it.
-mmin -N is minutes ago. -mtime -N is days ago.

Size — find what’s eating disk
Largest files in home (awk formats bytes → MB)
find ~ -type f -size +50M -printf '%s %p\n' | sort -rn | head -10 \
  | awk '{printf "%8.1fM  %s\n", $1/1048576, $2}'
Empty files (often leftover from failed operations)
find ~/atelier/_bibliotheca/domus-captures -type f -empty -printf '%p\n'
Counting and grouping — awk as the aggregator
Count file types in a directory tree
find ~/atelier/_bibliotheca/domus-captures -type f \
  | awk -F. '{print $NF}' | sort | uniq -c | sort -rn | head -15
Output (this system):
   8759 adoc
   3842 html
   1683 js
    657 ts
    637 age
    512 svg
    327 md
    294 json
    259 sh
    194 d2
Security audit — find what shouldn’t be there
Unencrypted files in data/ that might need encryption
find ~/atelier/_bibliotheca/domus-captures/data -type f \
  \( -name '*.adoc' -o -name '*.json' -o -name '*.yaml' \) \
  ! -name 'README.adoc' ! -path '*/shared/*' ! -path '*/education/*' \
  ! -path '*/sessions/*'

Multi-predicate logic: \( -o \) is OR, ! is NOT.
This finds plaintext that escaped the gitignore net — run before every push.

Duplicate detection
Find duplicate filenames across directories
find ~/atelier/_bibliotheca/domus-captures/docs -type f -name '*.adoc' \
  -printf '%f\n' | sort | uniq -d

-printf '%f\n' prints just the filename (no path).
uniq -d shows only lines that appear more than once.

Remote history capture (new pattern — first use today)
Capture a remote host’s shell history as an encrypted artifact
ssh kvm-01 "cat ~/.bash_history" \
  | tee data/d000/shell-history/kvm-01-bash-hist-"$(date +%F)"
echo y | encrypt-file data/d000/shell-history/kvm-01-bash-hist-"$(date +%F)"

tee writes to file and stdout — you see the output scroll while it’s captured.
$(date +%F) expands locally before ssh runs.
echo y pipes confirmation to the interactive "Remove original?" prompt.

-printf format reference
Format Meaning

%p

Full path

%f

Filename only (no directory)

%h

Directory only (no filename)

%s

Size in bytes

%TY-%Tm-%Td

Modified date (YYYY-MM-DD)

%TH:%TM:%TS

Modified time (HH:MM:SS.fractional)

%T@

Modified time as epoch seconds (best for sort)

%u

Owner username

%m

Permissions (octal)

Predicate reference
Predicate Meaning

-type f

Regular files only

-type d

Directories only

-name '*.adoc'

Glob match on filename

-path '/projects/'

Glob match on full path

-size +50M

Larger than 50MB (+ = greater, - = less)

-mmin -30

Modified within last 30 minutes

-mtime -1

Modified within last 24 hours

-newermt "2026-06-17"

Modified after this date

-empty

Zero-size files

! -path '/.git/'

Exclude .git directories

\( -o \)

OR (must escape parens from shell)

-exec cmd {} \;

Run cmd per match (\; = one at a time)

-exec cmd {} +

Run cmd with batched matches (+ = faster)

-print0

Null-delimited output (safe for xargs -0)

Near-Miss: Glob Expansion Matched Pipeline Deletion Script

2026-06-17 — during screenshare

Incident

Attempted to build an AsciiDoc file using find with command substitution:

build-adoc $(find -name 'build-*.sh') html --variant light-cyan

The find -name 'build-*.sh' glob matched a shell script created to destroy a Monad pipeline. The command substitution expanded the match and passed it as an argument to build-adoc. This occurred during an active screenshare.

What prevented damage
  • dsu credential hygiene — API credentials had been unsourced after prior use (dsu clears all sourced vars). Even if the destructive script had somehow executed, it could not authenticate against the Monad API without sourced credentials.

  • build-adoc expected .adoc, not .sh — the tool did not execute the matched script, but the expansion itself was the danger.

Root cause

find -name 'build-.sh' is unbounded — it recursively matches every file matching the pattern in the current directory tree. Shell command substitution ($(…​)) expands the result *before the outer command sees it. There is no preview, no confirmation, and no scope restriction.

A destructive script named build-destroy-pipeline.sh or build-cleanup.sh is indistinguishable from build-adoc.sh to the glob pattern build-*.sh.

Lessons
Rule Rationale

Always echo or ls a glob before using it destructively

echo $(find -name 'build-*.sh') shows what will expand — zero cost, prevents accidents

Scope find to specific directories

find docs/ -name '.adoc' not find -name '.adoc' — limit the blast radius

Never use find with command substitution for destructive operations

Use find …​ -exec with explicit confirmation, or pipe through xargs -p for interactive approval

Name destructive scripts with a DANGER- or destroy- prefix

DANGER-delete-pipeline.sh will never match build-*.sh — naming convention as safety net

dsu after every ds session — no exceptions

Credential unsourcing is the last line of defense when everything else fails

Defensive patterns
Preview before execution
# SAFE: preview what find matches
echo $(find docs/ -name 'build-*.adoc')

# SAFE: interactive confirmation with xargs
find docs/ -name '*.adoc' | xargs -p -I{} build-adoc {} html --variant light-cyan

# SAFE: scoped find with explicit directory
build-adoc $(find docs/ -name 'self-eval*.adoc') html --variant light-cyan
Credential lifecycle
ds d001 lab/network    # Source — 87 vars loaded
# ... do work ...
dsu                    # Unsource — 87 vars cleared
# API calls now fail safely — no credentials in environment
Status
  • Severity: Near-miss (no data loss, no pipeline destroyed)

  • Exposure: Active screenshare — credentials were NOT visible (dsu had cleared them)

  • Action: Document as discovery, add to codex defensive scripting patterns

  • Graduate to: Codex (glob safety) after 3+ references

Shell Function: d001 Project Builder

Generic function that builds any d001 project: renders changed diagrams, builds all assemblers in parallel, opens results. Add to shell config for reuse across all projects.

The function
build_d001() {
  local project="${1:-$(pwd)}"
  local diagrams="$project/diagrams"
  local output="$project/output"
  local builder="$HOME/atelier/_bibliotheca/domus-asciidoc-build/bin/build-adoc.sh"

  printf 'Project: %s\n\n' "$project"

  printf 'Rendering changed DOT diagrams...\n'
  find "$diagrams" -type f -name '*.dot' -exec sh -c '
    for f do
      out="${f%.dot}.svg"
      if [ ! -e "$out" ] || [ "$f" -nt "$out" ]; then
        dot -Tsvg "$f" -o "$out"
        printf "  ✓ %s\n" "$out"
      else
        printf "  - current: %s\n" "$out"
      fi
    done
  ' sh {} + 2>/dev/null

  printf '\nBuilding AsciiDoc files...\n'
  find "$project" -maxdepth 1 -type f -name '*.adoc' -not -name 'README.adoc' -print0 | \
    xargs -0 -r -P3 -I{} "$builder" "{}" html --variant light-cyan

  printf '\nOpening fresh HTML output...\n'
  find "$output" -type f -name '*.html' -newer "$output" -exec firefox {} + &

  printf 'Done.\n'
}
Usage
# From anywhere — pass the project path
build_d001 data/d001/projects/siem-qradar-to-sentinel

# From inside the project directory
cd data/d001/projects/tcp-clocks
build_d001

# Any d001 project with assemblers at root + diagrams/ dir
build_d001 data/d001/projects/ed-sewer-pump
What it does — three stages
Stage Tool Why

1. Diagrams

find -exec dot -Tsvg

Incremental — only renders .dot files newer than their .svg (-nt test)

2. Build

xargs -P3build-adoc.sh

Parallel — builds all assemblers simultaneously. Full path avoids alias issue.

3. Open

find -newer -exec firefox

Only opens freshly built HTML, not stale artifacts

Teaching points
  • -r on xargs — don’t run the builder if find returns nothing (no .adoc files)

  • -not -name 'README.adoc' — README is not an assembler, skip it

  • -nt (newer than) — shell test: [ "$f" -nt "$out" ] returns true if source is newer than output. Prevents redundant diagram rendering.

  • -newer in find — same concept: only match files modified after a reference point

  • Full path for build-adoc.shfind -exec and xargs don’t inherit shell aliases. Use ~/path/to/script.sh directly.

  • Never xargs -P bash -ic — interactive shells fight over TTY in parallel. Processes suspend with "tty input" error.

Where to put it

This is a shell function, not a project script. Add to:

# ~/.config/zsh/functions/build_d001.zsh or equivalent
# Then source in .zshrc

Not in data/d001/projects/siem-qradar-to-sentinel/scripts/ — it’s generic, not project-specific.

SSH + gopass Workflow for Git Push

The ssh-agent only runs in user’s terminal session. Claude’s shell cannot push. This is the manual workflow.

Load SSH key for GitHub
# 1. Copy passphrase to clipboard (clears in 45s)
gopass show -c v3/domains/d000/identity/ssh/github

# 2. Add key to agent — paste passphrase when prompted
ssh-add ~/.ssh/id_ed25519_github

# 3. Verify
ssh-add -l
ssh -T git@github.com
Why this works
  • gopass show -c copies the secret to clipboard without printing it to terminal

  • ssh-add loads the key into ssh-agent for the session — no re-entry until reboot or agent restart

  • The key comment (github-arch-2026) identifies which key is loaded when multiple keys are in the agent

SSH config overview

Post-quantum hardened config (~/.ssh/config, ARS-SEC-SSH-001 v3.0):

  • ML-KEM-768 + NTRU Prime key exchange (requires OpenSSH 9.0+)

  • Least privilege — no legacy cryptography by default

  • Exception blocks for hosts requiring legacy ciphers

  • Socket multiplexing: ~/.ssh/sockets/ for connection reuse

  • Encrypted at rest: ssh/.ssh/config.age tracked in git, plaintext gitignored

Adapt SSH config — TODO
  • Review exception blocks for work hosts (CHLA infrastructure)

  • Add any missing work jump hosts

  • Verify PQ KEX negotiation with home lab hosts

  • Test socket multiplexing performance with kvm-01/kvm-02 sessions

  • Re-encrypt after any edits: age -e -R ~/.age/recipients/self.txt -o ssh/.ssh/config.age ssh/.ssh/config

domus-captures — Git Workflow Reference

Complete workflow: authenticate, commit, push, verify via API. domus-captures pushes to both GitHub (origin) and GitLab (gitlab). Cloudflare Pages auto-deploys from origin on push.

Remotes
Name URL Purpose

origin

git@github.com:EvanusModestus/domus-captures.git

Primary — Cloudflare Pages deploys from here

gitlab

git@gitlab.com:evanusmodestus/domus-captures.git

Mirror

Step 1: Load SSH key

SSH agent is session-scoped — clears on reboot. Must reload after every boot.

Copy passphrase to clipboard (clears in 45s)
gopass show -c v3/domains/d000/identity/ssh/github
Load key — paste passphrase when prompted
ssh-add ~/.ssh/id_ed25519_github
Verify key loaded
ssh-add -l
Test connection
ssh -T git@github.com
Step 2: Check status
Working tree status
git status
Review changes before staging
git diff
Step 3: Stage and commit
Stage specific files (preferred — never git add -A blindly)
git add docs/modules/ROOT/partials/worklog/daily-notes/2026-06/2026-06-17/
Commit with heredoc for multi-line messages
git commit -m "$(cat <<'EOF'
docs(worklog): 2026-06-17 daily notes

- P16g regression: post-reboot dmesg evidence, MTP/lsblk explanation
- Copilot Lua merge prep: keybind collision fix, cmd list cleanup
- Rhetoric vocabulary: epithet, tricolon, isocolon figures
- Makefile: delegate export to build-antora-page.sh, fix nested includes
EOF
)"
Step 4: Push to remotes
Push to GitHub (triggers Cloudflare Pages deploy)
git push origin main
Push to GitLab mirror
git push gitlab main
Or push both in parallel
git push origin main & git push gitlab main & wait
Step 5: Verify via GitHub API

gh api takes REST endpoint paths with leading / — not subcommands.

Latest commit on remote
gh api /repos/EvanusModestus/domus-captures/commits --jq '.[0].commit.message | split("\n")[0]'
Repo metadata
gh api /repos/EvanusModestus/domus-captures --jq '{size_kb: .size, pushed: .pushed_at, default_branch: .default_branch, visibility: .visibility}'
Recent commits (last 5, formatted)
gh api /repos/EvanusModestus/domus-captures/commits --jq '.[:5] | .[] | "\(.sha[:7]) \(.commit.author.date[:10]) \(.commit.message | split("\n")[0])"'
Commits by date range (last 24h)
gh api "/repos/EvanusModestus/domus-captures/commits?since=$(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ)" --jq '.[] | "\(.sha[:7]) \(.commit.message | split("\n")[0])"'
File tree of last commit (what changed)
gh api /repos/EvanusModestus/domus-captures/commits/main --jq '.files[] | "\(.status) \(.filename)"'
Branch list
gh api /repos/EvanusModestus/domus-captures/branches --jq '.[].name'
Compare two refs (what would a PR contain)
gh api /repos/EvanusModestus/domus-captures/compare/main...HEAD --jq '{ahead: .ahead_by, behind: .behind_by, files: [.files[].filename]}'
Deployments (Cloudflare Pages)
gh api /repos/EvanusModestus/domus-captures/deployments --jq '.[:3] | .[] | {env: .environment, created: .created_at, description: .description}'
Quick reference — gh api patterns
Endpoint What it returns

/user

Authenticated user profile (login, public_repos, created_at)

/repos/{owner}/{repo}

Repo metadata (stars, forks, size, pushed_at, visibility)

/repos/{owner}/{repo}/commits

Commit history (default: 30, paginated). Add ?since= for date filter

/repos/{owner}/{repo}/commits/{ref}

Single commit detail with file list (status, filename, additions, deletions)

/repos/{owner}/{repo}/branches

Branch list with protection status

/repos/{owner}/{repo}/compare/{base}…​{head}

Diff between two refs — ahead_by, behind_by, file list

/repos/{owner}/{repo}/deployments

Deployment history (environment, status, created_at)

/repos/{owner}/{repo}/actions/runs

CI/CD workflow runs (if using GitHub Actions)

/repos/{owner}/{repo}/contributors

Contributor list with commit counts

/repos/{owner}/{repo}/languages

Language breakdown by bytes (Lua, AsciiDoc, etc.)

gh api — key syntax rules
Rule Example

Leading / required

/user not user

--jq for JSON filtering

--jq '.login' extracts a field

Query params with ?

"/repos/…​/commits?since=2026-06-17T00:00:00Z"

Pagination (default 30)

--paginate for all results, or ?per_page=100

No pager needed

gh api does not paginate output to a pager — output goes straight to stdout

Common mistake: gh api user (no slash) — gh interprets it as a subcommand and fails. Always use /user, /repos/…​.

Aliases — existing shell functions
Alias Expands to

gach

git add -A && git commit (heredoc message)

gacp

git add -A && git commit && git push

gpall

Push to all remotes

domus-push

Push domus-captures to origin

domus-check

Check domus-captures status

domus-nvim — Copilot Lua Merge Prep

Three commits on feature/copilot-lua: replace copilot.vim with copilot.lua + CopilotChat.nvim. Pre-merge cleanup: fix <leader>cf collision (Format lost when remapped to Fix), trim redundant cmd list, drop orphan CopilotChatOptimize.

Issue: <leader>cf collision

On main, <leader>cf = Format (conform.lua). On the branch, remapped to Fix code (CopilotChatFix). Format binding lost entirely.

Resolution: <leader>cf = Fix code (Copilot), <leader>cF = Format (conform).

Step 1: Find where Format is currently bound
cd ~/atelier/_projects/personal/domus-nvim
grep -rn 'format\|conform' lua/domus/plugins/specs/ lua/domus/plugins/config/ | grep -i 'leader\|keymap\|keys'
Result
lua/domus/plugins/config/conform.lua:57:    -- Manual format keymap

Format lives in conform.lua:57. Update its binding from <leader>cf to <leader>cF there.

Step 2: Add <leader>cF to which-key
Before
sed -n '66,73p' lua/domus/plugins/config/which-key.lua
Change
sed -i '71a\        { "<leader>cF", desc = "Format" },' lua/domus/plugins/config/which-key.lua
After
sed -n '66,75p' lua/domus/plugins/config/which-key.lua
Step 3: Trim redundant cmd list in coding.lua

The keys table already lazy-loads CopilotChat. The cmd list duplicates those triggers and includes CopilotChatOptimize which has no keymap.

Before
grep -n 'cmd = {' lua/domus/plugins/specs/coding.lua
Change
sed -i 's/cmd = { "CopilotChat", "CopilotChatExplain", "CopilotChatTests", "CopilotChatFix", "CopilotChatOptimize", "CopilotChatReview", "CopilotChatDocs" },/cmd = "CopilotChat",/' lua/domus/plugins/specs/coding.lua
After
grep -n 'cmd = ' lua/domus/plugins/specs/coding.lua
Step 4: Commit cleanup
git add -A
git commit -m "$(cat <<'EOF'
fix(copilot): restore Format bind as <leader>cF, trim CopilotChat cmd list

- <leader>cf was Format (conform), now Fix (CopilotChat) — add <leader>cF for Format
- Remove redundant cmd lazy-load triggers covered by keys table
- Drop orphan CopilotChatOptimize from cmd (no keymap)
EOF
)"
Step 5: Load SSH key and push feature branch

SSH agent is session-scoped — key must be loaded after every reboot. gopass copies the passphrase to clipboard (clears in 45s), then ssh-add loads the key.

gopass show -c v3/domains/d000/identity/ssh/github
ssh-add ~/.ssh/id_ed25519_github
Verify key loaded
ssh-add -l
Push feature branch
git push origin feature/copilot-lua
Step 6: Merge to main
git checkout main
git pull origin main
git merge feature/copilot-lua
Step 7: Push main
git push origin main
Step 8: Verify and clean up
Confirm merge
git --no-pager log --oneline -5
Delete feature branch (local + remote)
git branch -d feature/copilot-lua
git push origin --delete feature/copilot-lua
Step 9: Verify via GitHub API

gh api takes a REST endpoint path, not a subcommand. The leading / is required.

Confirm latest commit on remote
gh api /repos/EvanusModestus/domus-nvim/commits --jq '.[0].commit.message' | head -1
Your profile
gh api /user --jq '.login, .public_repos'
Repo metadata
gh api /repos/EvanusModestus/domus-nvim --jq '{stars: .stargazers_count, forks: .forks_count, pushed: .pushed_at, default_branch: .default_branch}'
Recent commits (last 5, no pager)
gh api /repos/EvanusModestus/domus-nvim/commits --jq '.[:5] | .[] | "\(.sha[:7]) \(.commit.message | split("\n")[0])"'
Branch list
gh api /repos/EvanusModestus/domus-nvim/branches --jq '.[].name'
Confirm feature branch is deleted on remote
gh api /repos/EvanusModestus/domus-nvim/branches --jq '.[].name' | grep copilot || echo "Branch deleted — clean"
Share URL for colleagues
gh api /repos/EvanusModestus/domus-nvim --jq '.html_url'

Common mistake: gh api user (no slash) — gh interprets user as a subcommand, not an endpoint. Always /user, /repos/…​, /orgs/…​.

Sharing with colleagues

The repo is ready. Give them:

git clone git@github.com:EvanusModestus/domus-nvim.git ~/.config/nvim

Prerequisites: Neovim 0.10+, a GitHub Copilot subscription, npm (for CopilotChat dependencies). On first launch, Lazy.nvim installs all plugins. Run :Copilot auth to authenticate.

Final keymap reference
Bind Action Source

<leader>ca

Code action

lsp

<leader>cc

Copilot chat

CopilotChat

<leader>cd

Generate docs

CopilotChat

<leader>ce

Explain code

CopilotChat

<leader>cf

Fix code

CopilotChat

<leader>cF

Format

conform.lua

<leader>cr

Review code

CopilotChat

<leader>ct

Generate tests

CopilotChat

<M-l>

Accept suggestion

copilot.lua

<M-]> / <M-[>

Next / prev suggestion

copilot.lua

<M-h>

Dismiss suggestion

copilot.lua

Education

Don Quijote — Lectura del día

Capítulo: XXXIX (Historia del cautivo, continuación)
Build: build-adoc data/d000/education/quijote-study/notas/p1-cap-039/p1-cap-039-notas.adoc html --variant light-cyan
Custom roles: .cervantes, .retorica, .testimonio, .teologia, .gramatica, .ironia, .pregunta

Lo que leí hoy

Escribe en español.

Vocabulario nuevo
Palabra Definición Ejemplo en contexto

palabra

definición

cita del texto

Retórica que encontré

Figuras retóricas del capítulo — conectar con el vocabulario retórico del día (epithet, tricolon, isocolon).

Conexiones con Cicerón

De Inventione, prólogo (líneas 42–92) — ¿qué conecta con lo que leíste hoy?

Notas para SIELE/DELE
  • Registro formal observado:

  • Estructura sintáctica compleja:

Rhetorical Vocabulary — Figures and Power Words

Building a working register of rhetorical figures and high-impact vocabulary for professional and technical communication. Each term earns its place through use, not memorization.

Figures of speech — structural
Figure Definition Example

Tricolon

Three parallel terms with ascending force

Documented, verified, repeatable.

Isocolon

Parallel clauses of equal length and structure

Methodical in structure, rigorous in verification, portable across colleagues.

Epithet

A characterizing phrase attached to a noun — compresses identity into description

Meticulously methodical. Swift-footed Achilles. Wine-dark sea.

Epitome

The perfect embodiment of a type — the thing itself, not the description

This workflow is the epitome of meticulously methodical engineering.

Congeries

Heaping synonyms for emotional weight — power through accumulation, not progression

Thoroughly, copiously, meticulously (three ways to say "carefully" — use deliberately or not at all).

Anaphora

Repetition at the start of successive clauses — builds momentum

We documented. We verified. We shipped.

Asyndeton

Deliberate omission of conjunctions — creates speed and urgency

Document, verify, ship.

Polysyndeton

Deliberate excess of conjunctions — creates weight and deliberation

Document and verify and test and ship.

The tricolon test

A tricolon must ascend. Each term adds something the previous lacked. If you can drop one term and lose nothing, it wasn’t earning its place.

Weak (congeries — synonyms)
Thoroughly, copiously, meticulously methodical
Strong (tricolon — progression)
Documented, verified, repeatable       (self → proof → audience)
Precise, defensible, transferable      (quality → evidence → portability)
Captured, validated, deployed          (record → test → action)
Power words — high-impact professional vocabulary
Word Use and context

Meticulous

Extreme care in detail. Stronger than "careful" — implies nothing overlooked. Meticulous documentation ensures repeatability.

Methodical

Systematic, ordered approach. Implies process, not luck. Methodical verification catches what ad-hoc testing misses.

Rigorous

Exhaustively thorough, intellectually uncompromising. Rigorous analysis of the dmesg output isolated the regression window.

Defensible

Can withstand scrutiny or challenge. Stronger than "correct" — implies evidence. Every configuration change must be defensible in a post-incident review.

Portable

Works in any context, not coupled to one person’s knowledge. Portable runbooks let any team member execute at 3 AM.

Authoritative

Speaks with earned credibility. The antora.yml attributes are the authoritative source for mutable values.

Canonical

The one true reference — all others derive from it. INC-2026-04-12 is the canonical example of verify-before-acting.

Deliberate

Intentional, not accidental. Implies agency and ownership. Deliberate difficulty builds durable skill.

Surgical

Precise intervention with minimal collateral effect. A surgical sed edit — one line changed, system-wide impact.

Durable

Built to last, not expedient. Durable patterns outlive the project that created them.

AsciiDoc — Data Table Formats Reference

Tables populated from structured data — CSV files, inline CSV, DSV, TSV. Single source of truth pattern: data lives in .csv, AsciiDoc renders it.

Three data formats
Format Delimiter Shorthand When to use

CSV

,

,===

Default choice. Most portable. Importable by Excel, awk, jq --raw-input.

TSV

tab (\t)

none — use format=tsv

Tab-delimited exports. Set format=csv + separator=\t as alternative.

DSV

:

:===

When data contains commas. Avoid for MAC addresses (colons collide).

Pattern 1: Inline CSV
[%header,format=csv]
|===
Name,Role,Status
Alice,Engineer,Active
Bob,PM,On Leave
|===
Pattern 2: CSV from file (reusable)
[%header,format=csv]
|===
include::../output/mac-list-all-clocks.csv[]
|===

The include:: pulls the CSV at build time. Edit the CSV, rebuild — table updates. One file feeds both the documentation and your awk/jq scripts.

Pattern 3: Shorthand notation
,===
Artist,Track,Genre

Baauer,Harlem Shake,Hip Hop
,===

The ,=== delimiter implies format=csv — no attribute needed. Add [%header] above to promote the first row.

Pattern 4: Collapsible with CSV include
.Full inventory (collapsible)
[%collapsible]
====
[%header,format=csv]
|===
include::../output/data.csv[]
|===
====

[%collapsible] wraps the table in a disclosure widget — click to expand. Keeps long tables from dominating the page.

Pattern 5: Column formatting on CSV data

CSV cells don’t support per-cell formatting. Use cols to format entire columns:

[%header,format=csv,cols="2,1,1"]
|===
include::data.csv[]
|===

cols="2,1,1" — first column gets 2x width. Add h for header style, a for AsciiDoc content:

[format=csv,cols="1h,2a"]
|===
Key,Value
Name,*Bold name*
|===
Escaping the pipe character in PSV tables

If cell content contains |, escape with \| or use |:

|===
| Command | Description

| grep foo \| wc -l
| Count matches
|===
Key rules
  • CSV/TSV: values can be enclosed in double quotes — "value with, comma"

  • CSV/TSV: empty lines are skipped (unless inside quotes)

  • DSV: escape delimiter with backslash — value\:with\:colons

  • Ragged tables: cells shuffle to fill rows (not padded like Excel)

  • No per-cell spans in data tables — use PSV (|===) for row/column spans

Work — Exchange

Exchange Online — Policy Changes

ConnectExchange policy enablement during call. Commands and policy details encrypted in d001.

Location

Commands and output: d001 open abnormalpartials/

Context
  • Call with:

  • Reason:

  • Ticket/CR:

  • Policies changed (names only, no config):

  • Related: Today’s worklog

Workflow Demo — Docs-as-Code for Infrastructure Engineering

Prep for call with senior Linux engineer. Show the full pipeline: encrypted project data → AsciiDoc partials → Graphviz diagrams → single-command builds → PDF/HTML output. Everything version-controlled, everything reproducible.

Dispositio — Talk Structure

Exordium (hook — 30 seconds):

"Every project I work on — ISE onboarding, SIEM migration, Exchange policies — follows the same workflow. I write the commands, the notes, the diagrams, and the comms in AsciiDoc partials. One command builds a complete project document with topology diagrams, API queries, and email drafts. Everything is encrypted at rest, version-controlled in git, and deployable to a static site."

Narratio (the problem — 1 minute):

  • Confluence/SharePoint: stale the day it’s written, no version control, no CLI integration

  • OneNote/Word: can’t include code blocks with syntax highlighting, can’t grep across projects

  • Tribal knowledge: the commands that solved the problem live in someone’s terminal history, not in a searchable system

Propositio (the thesis — 15 seconds):

"Infrastructure documentation should be written in the same tools and workflows as infrastructure code."

Confirmatio (the proof — live demo, 5 minutes):

Demo 1: Project lifecycle (tcp-clocks)
Open encrypted project
d001 open tcp-clocks
Show the structure — one concern per file
ls data/d001/projects/tcp-clocks/partials/
Show the assembler — partials compose into a single document
cat data/d001/projects/tcp-clocks/tcp-clocks.adoc
Build HTML with one command
build-adoc $(find -name 'tcp-clocks.adoc') html --variant light-cyan
Open in browser — full document with diagram, tables, code blocks
firefox data/d001/projects/tcp-clocks/output/tcp-clocks.html &
Demo 2: Diagrams as code (Graphviz)
Show the diagram source — plain text, version-controlled
cat data/d001/projects/tcp-clocks/images/tcp-clocks-profiling-chain.dot
Render SVG
dot -Tsvg data/d001/projects/tcp-clocks/images/tcp-clocks-profiling-chain.dot -o /tmp/demo.svg
firefox /tmp/demo.svg &

Key point: the diagram is diffable in git. When the profiling chain changes, git diff shows exactly what changed in the topology — not a binary blob.

Demo 3: Extract content with CLI tools
Extract an email draft from a structured document
sed -n '/^Hi \[Medigate/,/^Evan$/p' $(find -name 'comms-2026-06-17-medigate-attributes.adoc')
Search across all projects by content
grep -rnw 'assetVendor' $(find data/d001 -name '*.adoc' -not -name '*.age')
Count endpoints by status from CSV
awk -F, 'NR>1 {s[$3]++} END {for (k in s) printf "%s: %d\n", k, s[k]}' data/d001/projects/tcp-clocks/output/mac-list-all-clocks.csv

Key point: the documentation IS the data. You don’t export from a GUI and paste into a doc — the doc contains the queries, the queries produce output, the output feeds the next query.

Demo 4: Encryption at rest
Close encrypts all partials, deletes plaintext
d001 close tcp-clocks
Only .age files tracked in git — plaintext never leaves the machine
ls data/d001/projects/tcp-clocks/partials/*.age | head -5
Reopen on any machine with the age key
d001 open tcp-clocks
Demo 5: Daily worklog system
Today’s worklog — 15 partials, one page
ls docs/modules/ROOT/partials/worklog/daily-notes/2026-06/2026-06-17/
Build today’s worklog as PDF
./scripts/build-antora-page.sh docs/modules/ROOT/pages/2026/06/WRKLOG-2026-06-17.adoc pdf --theme light-cyan
Push deploys to static site automatically
git push origin main
# → Cloudflare Pages builds → https://docs.domusdigitalis.dev
Peroratio (close — 30 seconds):

"The infrastructure I manage is complex — ISE, SIEM, Exchange, Claroty, 165 IoT devices. The documentation system has to match that complexity without adding friction. AsciiDoc + git + CLI tools + encryption gives me a workflow where writing documentation is the same act as doing the work. The notes I take while solving a problem ARE the documentation."

Philosophy — why this works
Principle Implementation

Single source of truth

Partials hold content once. Pages and assemblers are shells with include:: directives.

One concern per file

context.adoc, queries-ers.adoc, session-2026-06-17.adoc — never a monolith.

Verify-before, change, verify-after

Every command block in the docs follows the same pattern the infrastructure follows.

Encryption at rest

d001 open/close — age encryption. Plaintext only exists while you’re working. Git tracks .age files only.

Diagrams as code

Graphviz .dot files — diffable, rebuildable, Catppuccin themed. dot -Tsvg renders.

CLI-native

sed, awk, grep, jq — the same tools that manage infrastructure also manage documentation. No context switch.

Automatic deployment

git push → Cloudflare Pages builds Antora site. No manual deploy step.

Repos to show (if asked)
ls ~/atelier/_bibliotheca/domus-*/
  • domus-captures — worklogs, projects, sessions, codex (this repo)

  • domus-infra-ops — infrastructure runbooks

  • domus-ise-linux — 802.1X EAP-TLS documentation

  • domus-docs — Antora aggregator hub

  • domus-asciidoc-build — build toolchain with custom themes

Discoveries

Discovery: EAP-TEAP Compiled into Arch wpa_supplicant

2026-06-17 ~23:30 — confirmed via `strings $(which wpa_supplicant) | grep -i teap`

Finding

Arch Linux wpa_supplicant ships with EAP-TEAP support compiled in. Key string found: OpenSSL: Enable cipher suites for anonymous EAP-TEAP provisioning.

This means Linux endpoints can authenticate via EAP-TEAP using the same ISE policy sets as Windows — no separate enrollment architecture required for the MSCHAPv2 migration.

Verification commands
# Confirm TEAP support
wpa_supplicant -h 2>&1 | grep -i teap
strings $(which wpa_supplicant) | grep -i teap
wpa_supplicant.conf — EAP-TEAP with inner MSCHAPv2
network={
    ssid="CHLA-Secure"
    key_mgmt=WPA-EAP
    eap=TEAP
    identity="user@chla.usc.edu"
    anonymous_identity="anonymous@chla.usc.edu"
    phase2="auth=MSCHAPV2"
    ca_cert="/etc/ssl/certs/chla-ca.pem"
}
wpa_supplicant.conf — EAP-TEAP with inner EAP-TLS (cert-based)
network={
    ssid="CHLA-Secure"
    key_mgmt=WPA-EAP
    eap=TEAP
    identity="user@chla.usc.edu"
    anonymous_identity="anonymous@chla.usc.edu"
    phase2="auth=TLS"
    ca_cert="/etc/ssl/certs/chla-ca.pem"
    client_cert="/etc/ssl/certs/client.pem"
    private_key="/etc/ssl/private/client.key"
}
Tomorrow (2026-06-18)
  • Test EAP-TEAP against ise-01 on kvm-01 (lab)

  • Create ISE authorization policy for Linux EAP-TEAP

  • Document wired 802.1X variant (wpa_supplicant with wired driver)

  • Check if Rocky 9 / Ubuntu Noble ship TEAP-enabled wpa_supplicant

  • Update Linux Research project with finding

Session Summary

Session Summary — 2026-06-17

18 partials produced. Multiple d001 projects advanced. Infrastructure changed in production.

Makefile & Build System
  • Fixed make export-today — delegated PDF/HTML/DOCX/EPUB to build-antora-page.sh (recursive partial$ resolution)

  • Fixed DOCX/EPUB pipeline — route through HTML intermediate instead of docbook5 (avoids nested markup XML error)

  • Changed default PDF theme to light-cyan (Noto Sans font issue with dark theme)

  • Discovered modules/ROOT/pages/2026/06/images required for standalone AsciiDoc builds — saved to memory

P16g Regression (Kernel 7.0.11)
  • Documented post-reboot dmesg evidence — USB flapping (ONYX Palma 2 disconnect/reconnect in 17s)

  • Documented MTP vs lsblk distinction — MTP is protocol-level, not a block device

  • LG monitor USB controls functional — proving selective/intermittent USB failure

  • All 3 Thunderbolt ports binding — regression is downstream in USB power management

gocryptfs Credential Gate
  • Documented Claude Code authentication behavior — vault unmounted = Sonnet/unauthenticated, vault mounted = Opus/Max

  • Defense-in-depth: LUKS + gocryptfs double encryption for API credentials

domus-nvim — Copilot Lua Merge
  • Merged feature/copilot-lua to main — copilot.vimcopilot.lua + CopilotChat.nvim

  • Fixed <leader>cf keybind collision — Format moved to <leader>cF

  • Trimmed redundant cmd list, removed orphan CopilotChatOptimize

  • Shared with colleagues — clone-ready on main

TCP Clocks (d001)
  • 165 clocks — many lost identity group assignment overnight

  • Extended Step 2 API check — added profileId resolution via ers "/profilerprofile/{pid}"

  • Profile name resolution tested and proven in d000 lab: Winstars-Technology-Device

  • Added DataConnect queries (Steps 2b, 2c) — endpoint profile + authz rule from RADIUS auth

  • Added CoA reauth commands (Step 7) + port bounce with confirmation (Step 8)

  • Created MAC inventory partial with CSV — [%header,format=csv] table + awk export commands

  • Created Medigate email draft — requesting Claroty attribute push for all 165 clocks

  • Fixed all 73 bare ---- listing blocks across all partials

  • Created Graphviz profiling chain diagram (Catppuccin Mocha)

  • Added dc_query function directly in session file — paste-ready

ED Sewer Pump (d001 — new project)
  • Scaffolded full d001 project: README, assembler, 4 partials, images, Graphviz topology

  • CISO (Sarah) assigned — reaching out to Karen Patterson (PM) for device details

  • ISE response draft + Karen email draft

  • 7 ISE validation queries (identity groups, dACLs, profiling policies, logical profiles, ED switches)

  • 8-step action tracker

Exchange Online (d001)
  • Policy changes scaffold — breadcrumb in daily notes, actual commands in d001/abnormal-security

SIEM QRadar-to-Sentinel (d001)
  • Project audit: 25 includes verified, 0 broken. Deleted 8.2MB duplicate session dumps. Archived stale notes. Moved graphviz lesson to d000/education.

  • Assembler fix: moved monad-vs-dcr.adoc from partials/ to project root (STD-001). Updated build-monad-doc.sh. Verified both assemblers build clean.

  • Replaced ASCII topology with Graphviz rsyslog-collection-topology.dot (Catppuccin Mocha)

  • Added :imagesdir: modules/ROOT/pages/2026/06/diagrams to main assembler + modules/ROOT/pages/2026/06/images for screenshots

  • Updated build-monad-doc.sh: parallel builds, incremental diagram rendering, both assemblers

  • Switch 10.193.144.249 onboarded:

    • Configured: logging source-interface Vlan144, logging host, snmp-server trap-source Vlan144, logging origin-id hostname

    • Verified syslog arrives at CHLXSYSLOG01

    • Verified Monad receives events — monad-observe.sh live sample confirmed

  • Monad pipeline expanded: 15→17 nodes, 14→16 edges:

    • Created switch-sink output node + switch-route edge (single PATCH, slug-referenced)

    • Created switch-syslog-extract transform (ID: 9407d074)

    • Rewired: input-syslog → switch-extract → switch-sink

    • Applied 10 enrichment operations: source_type, facility, environment, collector, severity_tier, compliance_scope, retention_tier, pipeline_version, switch_name, location

    • Dropped pri key (saves ingestion cost)

    • Proven live output with all enrichment tags

  • 5 Monad API constraints documented:

    1. POST /edges deprecated — returns 404

    2. No multiple incoming edges per node

    3. No orphan root nodes — node + edge must be added together

    4. PATCH disables all nodes — must re-enable with enabled: true on every node

    5. Transform PATCH replaces entire object — always include name and description

  • Transform API discovery: type: "jq" with config.expression does NOT work. Only config.operations with add/drop_key/flatten. No regex extraction in transforms.

  • Quick-reference pattern: GET → jq modify → PATCH for adding/removing transform keys without retyping

ISE API Reference (d000 — new)
  • Unified reference: ERS, MnT, DataConnect, pxGrid, OpenAPI — 5 API surfaces

  • Assembler with cross-API workflow patterns (full audit, CoA with verify, batch profile resolution)

  • Profile name resolution tested: ers "/profilerprofile/{pid}" → proven in d000 lab

  • Graphviz topology diagram (Catppuccin Mocha)

  • Shared partials: pxGrid (4 stubs), OpenAPI (3 stubs)

  • ERS endpoints.adoc: group + profile name resolution pattern with test output

CLI Skills Learned
  • grep -w — whole-word matching prevents substring traps (MTP vs SMTP)

  • find | while read — aliases work in shell loop, not in find -exec

  • find -exec vs xargs -P — parallel builds with full path (never bash -ic)

  • sed -n '/start/,/end/p' — address range extraction (Medigate email from AsciiDoc)

  • awk '/pattern1/,/pattern2/' — range between delimiters

  • cat does not take -execfind finds, other tools process

  • AsciiDoc CSV tables: [%header,format=csv] with include:: from file

  • [%collapsible] for long tables

  • build_d001 shell function — generic d001 project builder with incremental diagrams + parallel

Education
  • Rhetoric vocabulary: epithet vs epitome, tricolon test, congeries, anaphora, asyndeton

  • Power words: meticulous, methodical, rigorous, defensible, portable, authoritative, canonical

  • Quijote cap XXXIX reading session scaffolded

  • Workflow demo prep for senior Linux engineer — dispositio structure, 5 live demos

Metrics
  • 18 daily note partials produced

  • 5 d001 projects touched (tcp-clocks, siem, ed-sewer-pump, abnormal, domus-nvim)

  • 1 d000 project created (ISE API reference)

  • 17 Monad pipeline nodes (from 15)

  • 16 Monad pipeline edges (from 14)

  • 1 switch onboarded end-to-end (config → syslog → rsyslog → Monad → enriched output)

  • 10 enrichment tags per switch event

  • 5 API constraints documented from production errors

  • 73 bare listing blocks fixed across tcp-clocks partials

  • 156 MAC addresses in CSV inventory

Ad-Hoc Requests

Ad-Hoc Requests

Capture walk-ups, Teams pings, and unplanned work here.

gocryptfs credential gate — Claude Code authentication

Claude Code requires API credentials at launch. Credentials are stored inside a gocryptfs vault (credentials), unmounted at rest.

Table 1. Behavior observed (2026-06-17)
State Result

Vault unmounted

Claude Code loads as Sonnet 4.6 / API Usage Billing / "Not logged in" — falls back to unauthenticated mode

After gcvault mount credentials

Claude Code loads as Opus 4.6 / Claude Max — full authenticated session

Security design
  • Credentials encrypted at rest via gocryptfs — reboot clears the mount

  • No plaintext credentials on disk until explicit gcvault mount

  • Failed auth is silent degradation (reduced model, no subscription), not a crash

  • Mount is session-scoped — survives sleep, cleared on reboot

This is intentional defense-in-depth: even with disk encryption (LUKS cryptroot + crypthome), the API credentials get a second layer via gocryptfs. The tradeoff is a manual mount step after every reboot.


Work (CHLA)

CHARGE TIME IN PEOPLESOFT - CRITICAL. Do this NOW before anything else.

Critical (P0)

Project Description Owner Status Due Blocker

Linux Research (Xianming Ding)

EAP-TLS for Linux workstations, dACL, UFW

Evan

BEHIND (72 days overdue)

02-24

Certificate "password required" - nmcli fix documented

iPSK Manager

Pre-shared key automation

Ben Castillo

BEHIND

 — 

DB replication issues

MSCHAPv2 Migration

Legacy auth deprecation — 6,227 devices, 5 waves. 6 batch SQL queries + 3-API endpoint profile script added (05-11). Report due.

Evan

25% — Report due, batch queries ready

05-30

Report to turn in

Research Segmentation

All endpoints to Untrusted VLAN

Evan

BLOCKED

 — 

CISO decision pending

Disaster Recovery

ISE DR scoping — dot1x closed mode = total blackout

Evan

Scoping

 — 

 — 

Mandiant Remediation

Copy 4/16 findings, Guest ACL lab, Q2 assessment

Evan

Active

 — 

 — 

SIEM QRadar → Sentinel

Full SIEM platform transition. Monad console error resolved 05-12. Secrets configured. Blocked on DCR creation (Rule ID + Stream Name). Azure private network policy unresolved.

Evan

Active — blocked on DCR

Q2 2026

Victor/Mauricio: create DCR, resolve Azure network policy

Abnormal Security

AI email platform — ESA cutover. CR assigned, CAB May 12 15:00. Implementation May 14 10:00.

Evan

Active — CAB today 15:00

05-14

Pre-CAB checklist: confirm Tyler, Jason, Sarah

High Priority (P1)

Project Description Owner Status Target

ISE 3.4 Migration

Upgrade from 3.2p9

Evan

Blocked — maintenance window needed

Q2 2026

Switch Upgrades

IOS-XE fleet update (C9300, 3560CX)

Evan

Pending

Q2 2026

Spikewell BYOD VPN

dACL SQL, AD group integration

Evan

Active

 — 

Strongline Gateway

MAC capture, Identity Group setup — 37 days aging

Evan

Active — David Rukiza assigned

 — 

Abnormal Security

AI email security platform research, ESA cutover timeline

Evan

Newly assigned

 — 

DMZ Migration

External services audit behind NetScaler

Evan

Audit phase

 — 

Firewall Audit (murus-portae)

EtherChannel query, prefilter, policy assignments

Evan

Scoping — ASA API creds needed

 — 

iPSK Manager HA

Server 2 config, TLS, SQL security audit

Evan

In progress

 — 

Sentinel KQL

Build proficiency, distinguish from team

Evan

Onboarding

 — 

VNC Blocking

Block and eliminate VNC protocol enterprise-wide

Evan

Active — Phase 0 (Discovery)

Mid-June 2026

Strategic (P2)

Project Description Owner Status

HHS Regulatory Compliance

New HHS security policies implementation

TBD

NOT STARTED

InfoSec Reporting Dashboard

PowerBI metrics for executives

TBD

NOT STARTED

EDR Migration (AMP → Defender)

Endpoint protection consolidation

TBD

NOT STARTED

Azure Legacy Migration

Modern landing zone

Team

In Progress

ChromeOS EAP-TLS

SCEP + Victor, Paul testing

Victor

In Progress

P0 — Critical / Blocking

Security & Compliance

  • ISE 3.2 Patch 10 upgrade — CVE-2026-20147 CVSS 9.9 / CVE-2026-20148. Propose maintenance window once patch confirmed on software.cisco.com.

  • ISE Advisory sa-ise-rce-traversal-8bYndVrZ — check Patch 10 availability

  • Mandiant Remediation — findings status tracked. Working session prep + defensive posture documented (comms-2026-04-24). Copy 4/16 updates into Excel at work. Guest ACL lockdown (WIR-M-01) pending lab validation. appendix-todos updated with MSCHAPv2 milestones.

  • Guest ACL update — guest redirect ACL work needed. Lab validate GUEST_CWA_REDIRECT_MAX_SECURITY in d000, then joint CR with NE. On today’s task list.

  • Disaster Recovery & Downtime Procedures — ISE top priority (dot1x closed mode = SPOF for network access)

    • ISE DR: Document failover sequence — PAN, MnT, PSN priority order

    • ISE DR: RADIUS dead-server detection on WLCs/switches — critical-auth VLAN fallback

    • ISE DR: Backup/restore procedures — scheduled config backups, tested restores

    • FTD/FMC DR: FMC loss = no policy management

    • Network DR: Core/distribution switch failure, STP reconvergence, HSRP failover

    • Document RTO/RPO per system

SIEM Migration (QRadar → Sentinel)

  • SIEM QRadar → Sentinel Migration — LEAD ROLE. 4 collection iterations (Apr 16, 17, 17-streamlined, 20-streamlined). Python chart pipeline built (qradar-charts.py). Migration XLSX generated. Verification pending. Comms sent Apr 23.

    • d001 artifacts: 8 JSON exports, 2 CSV inventories, migration XLSX, top5 source SVG/PNG, verification doc

    • Dependency: Monad pipeline for log source transition

    • Dependency: Sentinel KQL proficiency for query migration

  • Monad Pipeline Evaluation (origin: 2026-03-11) — lead role. Console error RESOLVED 05-12. 06-09: Architecture decision — rsyslog (CHLXSYSLOG01) as collection tier → Monad → Sentinel. ISE lab → rsyslog → Monad 6-step execution guide created with 10 API calls. ASA lab logs already flowing through rsyslog. DCR still needed — Victor + Mauricio.

  • Sentinel KQL — build proficiency, distinguish from team. Azure portal access acquired.

  • QRadar log source report — run AQL queries, fetch JSON, generate Python Excel

Active Deployments & Migrations

  • MSCHAPv2 Migration — 6-sheet Standard Report ready. Migration window 05-04 to 05-30 CLOSED. Confirm final report status and next steps with team. 6,227 MSCHAPv2 devices, 14,249 EAP-TLS/TEAP (70% migrated).

  • MSCHAPv2 weekly cadence — recurring Wednesday call established (first 04-22). Completed 2026-04-22.

  • MSCHAPv2 ownership matrix — sent in scoping email 4/24 with manager callouts (@Albert, @John). Completed 2026-04-24.

  • TCP Clocks deployment — Batch 1: 7 clocks validated (OUI 40:AC:8D). Batch 2 (06-09): 9 new MACs (OUI 40:AC:BD) added via ERS. 1 one-off reassigned. New switch deployed without RADIUS/AAA — clocks can’t authenticate. Switch onboarding template + 3 validation queries documented. ERS queries self-contained with ers function.

  • SRT Research VLAN — confirm roles with Tony Sun: Tony implementor, Evan tester. CAB approved 04-21.

  • Downtime Computers enforcement — draft ISE AuthZ rule: medigate_724 + Wireless = DenyAccess. Separate CR. d001: DC queries, audit CSVs (v1-v3), wireless violations report delivered 04-21.

  • Enterprise Linux 802.1X — standardize Shahab/Ding deployment (CISO priority). Overdue since 02-24. Blocked by nmcli cert fix. 06-15: Assembler build fixed (26 errors → 0). Segmentation document extension to 06-16. d001 open linux-research to work on it.

  • Abnormal Security — CR-2026-05-07. Implemented 05-13. 06-09 update: Full policy review — 20-section EOP validation commands rebuilt, Hoxhunt SCL-1 investigation (intentional bypass confirmed), sclizer junk folder triage (~800 emails), Outlook reactions audit added, Connect-ExchangeOnline msalruntime fix documented. ESA migration expansion in progress — priority to move off ESA to full environment.

    • Team: Cox/William, Landeros/Jason, Rosado/Evan, Naranjo/Mauricio, Sandoval/Carlos

  • ASA VPN: Okta RADIUS → Entra SAML — (NEW 06-09) 5-phase migration plan built. ASA baseline captured (2 tunnel groups: CHLA_CORPORATE_USERS, CHLA_BYOD_USERS). 6 ISE policy screenshots. Tony Sun (ASA), Justin Halbmann (Entra/Okta), Evan (ISE). VPN cert expires 07-28. PDF deliverable ready. Share with team this week.

Tube System Upgrade (NEW — 06-01)

  • Tube System Upgrade — iTrack 3528165. 15x 10" TS stations need MAC addresses added to ISE identity group IoT_Onboard. MACs received from vendor (C8:1A:FE:20:xx:xx series). Station list spans ICU (CTICU, PICU, BMT, NICU, NICCU), ED, Surgery, Trauma, Pharmacy. Vendor contact: John Genest. Rationale: manufacturer no longer supports current system; failure risks delayed/missed patient care.

BMS Controller Segmentation (MIGRATED — 06-09)

  • BMS Controller Segmentation — Full migration from Principia LaTeX to d001. 12 partials, 5 Mermaid diagrams, 4 legacy PDFs, ISE screenshots. d001 open bms-controller. Completed 2026-06-09.

BMS Device Inventory (NEW — 04-24)

  • BMS Device Inventory — 72 devices discovered across 37 switches (04-24). Profile-driven architecture (Claroty/Medigate). 16 queries built. Phase 0 complete. Next: cross-reference with Visio diagrams, classify by function, begin D2 diagrams. Cleanup: delete 4 orphaned test groups, migrate 4 retire-dACL devices, investigate 3 null-profile devices.

VNC Blocking (NEW — 05-11)

  • VNC Blocking — block and eliminate VNC enterprise-wide. Due mid-June 2026. Phase 0: discovery. January AQL query baseline to incorporate. Cross-reference BMS inventory for VNC-capable devices.

Investigations & Audits

  • Murus Portae (WAF) — Phase 0 discovery in progress. FMC cert expired. d001: DMZ NetScaler WAF investigation, zone map, architecture D2 diagrams (v1+v2 SVGs), FMC REST API reference guide, ops script. FMC API returning zero ACP rules — under investigation.

  • Firewall audit — FMC discovery inventory done (d001: fmc-discovery-2026-04-16). EtherChannel query, prefilter, policy assignments pending.

  • IoT Dr. Kim devices — RECURRING. All 4 MACs validated in IoT_iPSK_VLAN1620_Misc (04-24). v2 validation queries built with 7 deep analysis queries (group flapping, credential leakage, profile drift, NAS tracking, remediation timeline, deny audit, OUI scan). Revalidate — confirm no flapping since 04-24.

  • IoT device validation queries — v2 created with partials architecture, 16 queries across ERS/MnT/DataConnect/FMC. Completed 2026-04-24.

Stale Blockers (carried via carryover tracker)

  • k3s NAT verification — rule 170, 10.42.0.0/16 pod network (origin: 2026-03-09). 92 days. Blocks Wazuh indexer recovery → blocks SIEM visibility. Decide: test or defer to Q3.

  • Strongline Gateway VLAN fix — 8 devices wrong identity group (origin: 2026-03-16). 85 days. David Rukiza assigned — follow up on status.

Administrative

  • PeopleSoft — track time for current week

  • iTrack tickets — close open tickets

  • KQL library — build initial queries in codex + d001

  • Linux Research project — finalize and review

  • Tax filing 2025 (MFJ) — see encrypted case file in data/d000/personal/ for details and action items

P1 — Important

  • MSCHAPv2 action-item tracker — owner/status/next-steps per workstream

  • ISE admin MFA enforcement — recommendation tied to advisory (interim control pending Patch 10)

  • DMZ Migration — external services audit behind NetScaler. Linked to Murus Portae investigation.

  • Vocera/Wyse iTrack RCA — complete root cause report

  • GCC ISE Support — 3/4 nodes restored, PSN-04 deferred

  • Wazuh indexer recovery — blocked by k3s NAT (origin: 2026-03-09)

  • Vocera EAP-TLS Supplicant Fix (origin: 2026-03-12)

  • iPSK Manager HA — blocked by DB replication (Ben Castillo)

  • ISE 3.4 Migration — depends on Patch 10 completion first

  • Git history scrub — murus-portae-output.md + ise-analytics CSVs

  • Encrypt prep-cmds-2026-04-15.adoc — plaintext committed to git

  • ISE MnT Messaging Service — enable UDP syslog delivery (maintenance window needed)

Infrastructure (Personal)

  • Borg backups — test and validate on ALL systems (Razer, P16g, vault-01, bind-01, kvm-01, kvm-02)

  • Borg — verify backup script paths updated from dotfiles-optimus to dots-quantum

  • Borg — create initial archive for ThinkPad P16g if none exists

  • Libvirt VLAN hook debug on both KVMs

  • Te1/0/2 cable replacement and re-test

  • Vault Raft cluster — verify vault-01 rejoined

  • Fix EAP-TLS keyring/secrets issue on Razer workstation

Completed (confirmed — do not delete, archive only)

  • CR-2026-04-15 SRT Research VLAN — submitted to iTrack. Completed 2026-04-15.

  • CAB presentation 4/21 — SRT Research VLAN 233 → CHLA-Research. APPROVED. Completed 2026-04-21.

  • Downtime Computers wireless audit — 45 computers, 16 violating, v3 report delivered. Completed 2026-04-21.

  • Git identity fix — dots-quantum/git/.gitconfig email corrected. Completed 2026-04-21.

  • MSCHAPv2 10:30 meeting — next steps + ACL coordination. Completed 2026-04-17.

Service Requests (SR)

SR# Request Requestor Opened Status

3508542

Zoll cards connection issue

STALE — verify in iTrack

3508524

Disable dot1x on (2) network ports - 5th floor 3250 Wilshire (PXE-boot imaging issues)

STALE — verify in iTrack (issues persisted after disable)

3528165

Tube System Upgrade — 15 stations, MAC addresses for ISE IoT_Onboard identity group

Genest, John (vendor contact)

2026-06-01

NEW — MACs received, need ISE onboarding

Incidents (INC)

INC# Priority Description Opened SLA Status

1911859

Strongline Gateways in Miscellaneous Subnet

STALE — verify in iTrack (related to carryover P0)

Change Requests - Emergency (ECAB)

CR# Description Opened Scheduled Status

No emergency changes

Change Requests - Normal

CR# Description Opened Scheduled Status

No normal changes

Change Requests - Scheduled/Standard

CR# Description Opened Window Status

No scheduled changes

Change Requests - Root Cause / Post-Incident

CR# Description Related INC Opened Status

100451

Vocera Phones and Wyse devices went off network

STALE — verify in iTrack


Session Accomplishments (Claude Code)

Day-specific accomplishments here.


Personal

In Progress

Project Description Status Notes

k3s Platform

Production k3s cluster on kvm-01

Active

Prometheus, Grafana, Wazuh deployed

Wazuh Archives

Enable archives indexing in Filebeat

Active

PVC fix pending

kvm-02 Hardware

Supermicro B deployment

Active

Hardware ready, RAM upgrade done

Planned

Project Description Target Blocked By

Vault HA (3-node)

vault-02, vault-03 on kvm-02

Q2 2026 (slipped from Q1)

kvm-02 deployment

k3s HA (3-node)

Control plane HA

Q2 2026 (slipped from Q1)

kvm-02 deployment

ArgoCD GitOps

k3s GitOps deployment

After k3s stable

 — 

MinIO S3

Object storage for k3s

After ArgoCD

 — 

Domus Inventory

Personal asset management (YAML + CLI + AsciiDoc)

Q2 2026

Schema approved

Active — Infrastructure

Task Details Priority Status Due

Wazuh agent deployment

Deploy agents to all infrastructure hosts

P2

Pending

After archives fix

k3s Platform

Production k3s cluster on kvm-01

P1

In Progress

 — 

Wazuh Archives

Enable archives indexing in Filebeat, PVC fix

P1

In Progress

 — 

kvm-02 Hardware

Supermicro B deployment, RAM upgrade done

P1

In Progress

 — 


Active — Security & Encryption

Task Details Priority Status Due

Configure 4th YubiKey

SSH FIDO2 keys

P1

TODO

 — 

Cold storage M-DISC backup

age-encrypted archives

P1

TODO

After YubiKey setup


Active — Development & Tools

Task Details Priority Status Due

netapi Commercialization

Go CLI rewrite with Cobra-style argument discovery, package for distribution

P0

Active

 — 

Ollama API Service

FastAPI (17 endpoints), productize — config audit, doc tools, runbook gen

P0

Active

 — 

Shell functions (fe, fec, fef)

File hunting helpers

P3

TODO

 — 


Active — Documentation

Task Details Priority Status Due

D2 Catppuccin Mocha styling

domus-* spoke repos (177 files total)

P3

In Progress

 — 


Active — Financial

Task Details Priority Status Due

Amazon order history import

Download CSV from Privacy Central → parse with awk → populate subscriptions tracker

P1

Waiting

Pending Amazon data export (requested 2026-04-04)


Active — Education

Task Details Priority Status Due

No active education tasks — see education trackers


Active — Personal & Life Admin

Task Details Priority Status Due

ThinkPad T16g Setup

Arch install, stow dotfiles, Ollama stack, netapi dev env

P0

Pending

 — 

P50 Arch to Ubuntu migration

CR-2026-03-12

P2

In Progress

 — 

X1 Carbon Ubuntu installs

2 laptops, LUKS encryption

P2

In Progress

 — 

P50 Steam Test

Test Flatpak Steam + apt cleanup of broken i386 packages

P3

Pending

 — 

Documentation Sites

Notes

Day-specific personal notes here.


Education

Claude Code Mastery

Resource Details Progress Status

Claude Code Full Course (4 hrs)

Nick Saraev - YouTube comprehensive course

26:49 / 4:00:00

IN PROGRESS

Claude Code Certification

Anthropic official certification (newly released)

Not started

GOAL

Skills Mastery (Critical)

Certification Deadlines

  • CISSP - July 12, 2026 (10-week plan active — Week 1)

  • RHCSA 9 - Q3 2026 (after CISSP)

  • LPIC-1 - Renewal required (blocks LPIC-2)

Spanish C1 Certification Goals

Certification Provider Target Status Strategy

SIELE C1

Instituto Cervantes / UNAM / Salamanca

Q2 2026

ACTIVE

Computer-based, faster results - take FIRST

DELE C1

Instituto Cervantes

Q3/Q4 2026

PLANNED

After SIELE success, harder exam

DELE C2

Instituto Cervantes

2027

FUTURE

Mastery level - requires extensive immersion

SIELE is computer-adaptive, results in 3 weeks. DELE is paper-based, results in 3-4 months. Do SIELE first to validate readiness.

Don Quijote Writing Practice - DELE C1/C2 Initiative

Method:

  1. Read chapter in original Spanish

  2. Write personal analysis/understanding en espanol

  3. AI review for grammar, vocabulary, register

  4. Build comprehensive understanding of literary elements

Today’s Study

  • Focus: CISSP (41 days to July 12 exam — schedule exam today 06-01), MSCHAPv2 migration wrap-up

  • Secondary: RHCSA curriculum, Spanish SIELE C1

  • CISSP — Security & Risk Management (continuing). Schedule exam this afternoon.

  • RHCSA — continue curriculum phase

  • Spanish — Don Quijote reading + analysis (DTLA study day)

  • MSCHAPv2 — migration window closed 05-30, review final report

Regex Training (CRITICAL)

  • Status: 52 days carried over (since 2026-03-16)

  • Priority: After PeopleSoft, before Quijote

  • Session: Character classes, word boundaries


Infrastructure

Documentation Sites

Site URL Status Actions Needed

Domus Digitalis

docs.domusdigitalis.dev

Active

Validate, harden, improve

Architectus

docs.architectus.dev

Active

Public portfolio site - maintain

HA Deployment Status

System Description Status Notes

VyOS HA

vyos-01 (kvm-01) + vyos-02 (kvm-02) with VRRP VIP

✅ COMPLETE

2026-03-07 - pfSense decommissioned

BIND DNS HA

bind-01 (kvm-01) + bind-02 (kvm-02) with AXFR

✅ COMPLETE

Zone transfer operational

Vault HA

Raft cluster (vault-01/02/03)

✅ COMPLETE

Integrated with PKI

Keycloak Rebuild

keycloak-01 corrupted, rebuild from scratch

🔄 NEXT

Priority P3 - SSO broken

FreeIPA HA

ipa-02 replica planned

📋 PLANNED

Linux auth redundancy

AD DC HA

home-dc02 replication

📋 PLANNED

Windows auth redundancy

iPSK Manager HA

ipsk-mgr-02 with MySQL replication

📋 PLANNED

PSK portal redundancy

ISE HA

PAN HA (ise-01 reconfigure)

⏳ DEFERRED

Wait until ise-02 stable

ISE 3.5 Migration

Upgrade path: 3.2p9 → 3.4 (P1) → 3.5 (target)

📋 PLANNED

After 3.4 Migration completes (Q2 2026)

Single Points of Failure (CRITICAL)

These systems have NO redundancy - outage impacts production.
System Impact if Down Mitigation

ISE (ise-02)

All 802.1X stops - wired and wireless auth fails

ise-01 reconfiguration deferred until ise-02 stable

Keycloak (keycloak-01)

SAML/OIDC SSO broken (ISE admin, Grafana, etc.)

NEXT PRIORITY - Rebuild runbook

FreeIPA (ipa-01)

Linux auth, sudo rules, HBAC fails

ipa-02 replica planned

AD DC (home-dc01)

Windows auth, Kerberos, GPO fails

home-dc02 replica planned

iPSK Manager

Self-service PSK portal unavailable

ipsk-mgr-02 with MySQL replication planned

Validation Tasks

Task Details Status

docs.domusdigitalis.dev validation

Test all cross-references, search, rendering

TODO

docs.domusdigitalis.dev hardening

HTTPS, CSP headers, security review

TODO

docs.architectus.dev validation

Public site content review

TODO

Hub-spoke sync verification

All components building correctly

Ongoing


Quick Commands

Git & GitHub CLI

create GitHub repo from existing local repo
gh repo create <name> --private --source . --remote origin --push
clone a forked repo into a specific directory
gh repo clone EvanusModestus/PowerShell ~/atelier/_projects/work/PowerShell
gh repo clone defaults to SSH. If key is passphrase-protected, load agent first: eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_ed25519_github
cross-repo commit search — all domus repos on a specific date
for repo in ~/atelier/_bibliotheca/domus-*/ ~/atelier/_projects/personal/domus-*/; do
  [ -d "$repo/.git" ] || continue
  name=$(basename "$repo")
  git -C "$repo" log --since="2026-04-06" --until="2026-04-07" --format="%h %aI %s" 2>/dev/null |
    awk -v r="$name" '{print r, $0}'
done
commit history touching only today’s modified files
git log --oneline -- $(find . -name "*.adoc" -type f -newermt "$(date +%F)")
unstage a file without losing changes
git restore --staged data/d001/api/ise-dataconnect/output/output-2026-04-24

Safe — removes from staging area only. Working tree is untouched. Use when you accidentally git add a plaintext or output file.

gh CLI — repo discovery and filtering

list repos by name pattern (domus/antora ecosystem)
gh repo list --limit 100 --json name,description \
  | jq -r '.[] | select(.name | test("domus|antora|asciidoc"; "i")) | "\(.name)\t\(.description)"'
top 20 most recently updated repos
gh repo list --limit 100 --json name,description,updatedAt \
  | jq -r 'sort_by(.updatedAt) | reverse | .[:20] | .[] | "\(.updatedAt[:10])\t\(.name)\t\(.description)"'
top 10 repos by disk usage
gh repo list --limit 100 --json name,diskUsage \
  | jq -r '.[] | "\(.diskUsage)\t\(.name)"' | sort -rn | head -10
clone a repo that’s not local yet
gh repo clone EvanusModestus/<repo-name> ~/atelier/_bibliotheca/<repo-name>

find & grep

files modified since midnight today (precise — not "last 24 hours")
find . -name "*.adoc" -type f -newermt "$(date +%F)" | sort
-mtime 0 means "last 24 hours", not "today". -newermt "$(date +%F)" compares against midnight — exact.
case-insensitive file search
find . -iname "*mschap*" -type f | sort
multiple name patterns with -o
find . -type f \( -iname "*ise*" -o -iname "*mschap*" \) | sort
same thing, single regex — fewer parens, extensible
find . -type f -iregex '.*\(ise\|mschap\).*'
exclude directories
find . -type f -iname "*meeting*" \
  -not -path "*/node_modules/*" \
  -not -path "*/.git/*" \
  -not -path "*/build/*"
recent drafts by modification time (newest first)
find .drafts -type f -printf '%T@ %Tc %p\n' | sort -rn | awk '{$1="";print}' | head -3
grep — know what you’re counting
grep -rl "pattern" . --include="*.adoc"         # file count (which files)
grep -rn "pattern" . --include="*.adoc"         # line matches (every occurrence)
grep -rc "pattern" . --include="*.adoc" | grep -v ':0$'  # match count per file
search with context — avoid opening the file
grep -rn -E 'git init|gh repo create' docs/ --include='*.adoc' -B2 -A2

Search codex by content — which files contain a command?

find all PowerShell files that use a specific cmdlet
find docs/modules/ROOT/examples/codex/powershell -type f -name "*.adoc" \
  -exec grep -l 'Get-Process\|Start-Process\|pipeline\|Where-Object' {} \;

Pattern: find -exec grep -l returns only filenames with matches — like grep -rl but with find’s `-type f -name filtering. Use \| for OR in grep basic regex. Swap the pattern for any cmdlet or keyword to locate coverage across the codex.

inventory a codex tool directory — count files per tier
find docs/modules/ROOT -name "powershell" -type d \
  -exec sh -c 'echo "$1: $(find "$1" -type f | wc -l) files"' _ {} \;
find orphaned examples (not included by any page)
for f in $(find docs/modules/ROOT/examples/codex/powershell -name "*.adoc" -type f); do
  base=$(basename "$f")
  dir_parent=$(basename $(dirname "$f"))
  grep -rq "$dir_parent/$base" docs/modules/ROOT/pages/codex/powershell/ \
    docs/modules/ROOT/examples/codex/powershell/*.adoc 2>/dev/null \
    || echo "ORPHAN: $f"
done

find → grep → open in nvim

find by path + content, open result in nvim
nvim $(find -path '*oauth*' -name '*.adoc' -type f \
  -exec grep -l 'timeout\|expire\|reconfig\|token' {} \;)

Command substitution $(…​) feeds all matches as arguments to nvim — opens every hit as a buffer. :bn/:bp to cycle, :ls to list. One file? Opens directly. Five files? All loaded, ready to navigate.

find by content across entire tree, open in nvim
nvim $(find docs/modules/ROOT -name '*.adoc' -type f \
  -exec grep -l 'token.*expire\|oauth.*refresh' {} \;)
open one at a time (sequential — -exec nvim per match)
find -path '*oauth*' -name '*.adoc' -type f \
  -exec grep -l 'timeout\|expire' {} \; \
  -exec nvim {} \;
Trailing \| in grep patterns matches empty string — every file matches. Always end with a term, not a pipe: 'timeout\|expire\|token' not 'timeout\|expire\|token\|'.

Trace Antora partial inclusion chains

who includes this partial? (one level up)
grep -rl 'commands/shell' docs/modules/ROOT/partials/
count all pages that include a partial
grep -rl 'quick-commands' docs/modules/ROOT | wc -l
full chain: partial → assembler → every page that uses it
file="commands/shell"
grep -rl "$file" docs/modules/ROOT/partials/ | while read f; do
  parent=$(basename "$f" .adoc)
  echo "$file -> $parent"
  grep -rl "$parent" docs/modules/ROOT/pages/ | while read p; do
    echo "  -> $(basename "$p")"
  done
done

Pattern: grep -rl finds which files contain the string. Chain two passes — first finds the assembler partial, second finds every page that includes it. Works for any partial in the Antora include hierarchy.

Multi-pattern file search — worklog partial discovery

brute force — one find per partial name
find docs/modules/ROOT -name "*urgent.adoc*" -type f
find docs/modules/ROOT -name "*morning.adoc*" -type f
consolidated — single find with regex (production approach)
find docs/modules/ROOT -type f -regextype posix-extended \
  -regex '.*(urgent|morning|work-chla|personal|education|infrastructure|quick-commands|related)\.adoc' \
  | sort

Pattern: -regextype posix-extended enables | alternation without escaping. One process, one sort — versus 8 separate finds. The sort deduplicates visually and groups by path.

pipeline alternative — find piped to grep
find docs/modules/ROOT -type f -name "*.adoc" \
  | grep -E 'urgent|morning|work-chla|personal|education|infrastructure|quick-commands|related'

Trade-off: the pipeline version is more readable but spawns two processes. The regex version is a single find — faster on large trees, same result.

Cross-repo literary term search — bibliotheca-wide discovery

When searching for a term across the entire _bibliotheca (multiple repos, mixed file types), these patterns escalate from narrow to broad.

1. Single repo — count matches per file
grep -rn --include='*.adoc' -c 'sanchuelo' . | grep -v ':0$'
2. Cross-repo — filenames only (all bibliotheca)
grep -rl --include='*.adoc' -i 'sanchuelo' ~/atelier/_bibliotheca/ | sort
3. Cross-repo with context — see the line in situ
grep -rn --include='*.adoc' -i -B1 -A1 'sanchuelo' ~/atelier/_bibliotheca/domus-captures/
4. Multi-filetype — .adoc + .txt (catches source texts)
grep -rl -i 'sanchuelo' ~/atelier/_bibliotheca/ --include='*.txt' --include='*.adoc' | sort
5. Null-safe find + xargs — handles spaces in paths
find ~/atelier/_bibliotheca/ -type f \( -name '*.adoc' -o -name '*.txt' \) -print0 \
  | xargs -0 grep -li 'sanchuelo' | sort
6. Open all hits directly in nvim
grep -rl -i 'sanchuelo' ~/atelier/_bibliotheca/ --include='*.adoc' --include='*.txt' | xargs nvim

Pattern escalation: #1 confirms the term exists and where. #2 expands to all repos. #3 shows context without opening files. #4 adds plain text sources (Quijote .txt originals). #5 is the safe version for automation. #6 opens everything for editing.

Trade-off: grep -r --include is faster for known file types. find | xargs grep is safer for paths with spaces and more extensible (add -name '*.md' etc.). For literary searches across the bibliotheca, #4 or #5 is usually the right starting point — the source texts are .txt, not .adoc.

Search daily notes — find commands, builds, and patterns across worklogs

Source: 2026-06-22 — searching for build-antora-page invocations and theme usage across partials

which daily note partials mention a command?
# Find files — filenames only
grep -rl 'build-antora-page' docs/modules/ROOT/partials/worklog/
see the match in context without opening the file
# 3 lines of context around each hit
grep -rn -C3 'build-antora-page' docs/modules/ROOT/partials/worklog/
search for any theme flag across all partials (PCRE alternation)
grep -rPn 'theme\s+(light-cyan|catppuccin|mocha)' docs/modules/ROOT/partials/
find + grep — search all daily note partials for build/export patterns
find docs/modules/ROOT/partials/worklog/daily-notes -name '*.adoc' \
  -exec grep -l 'build-antora-page\|build-adoc\|--theme\|pdf' {} \;
find + awk — show filename:matching_line for every hit (no -r needed)
find docs/modules/ROOT/partials/worklog/daily-notes -name '*.adoc' \
  -exec awk '/build-antora-page|build-adoc|--theme/{print FILENAME": "$0}' {} \;
awk state machine — extract full [source,bash] blocks containing a command
find docs/modules/ROOT/partials -name '*.adoc' -exec \
  awk '/^\[source,bash\]/{block=1; buf=""} \
       block{buf=buf"\n"$0} \
       /^----$/ && block>1{if(buf~/build-antora-page/) print FILENAME":"buf; block=0} \
       block{block++}' {} \;

The awk state machine: [source,bash] sets block=1 and starts buffering. Each line appends to buf. When the closing ---- arrives (and block>1 to skip the opening fence), check if the buffer contains the target command. If yes, print filename + entire block. Reset. One pass, arbitrary block size, no temp files.

sed address range — print only lines between code fences matching a pattern
find docs/modules/ROOT/partials/worklog -name '*.adoc' -exec \
  sed -n '/\[source,bash\]/,/^----$/{/build-antora-page/p}' {} +
search data/ too — standalone adoc outside Antora
grep -rn 'build-antora-page\|build-adoc' data/ --include='*.adoc'
every invocation sorted by path (chronological by date directory)
grep -rn 'build-antora-page' docs/modules/ROOT/partials/worklog/daily-notes/ \
  | awk -F: '{print $1, $3}' | sort

Pattern escalation: grep -rl → "where is it". grep -rn -C3 → "what’s around it". find -exec awk → "extract the structured block". sed address ranges → "print between delimiters". Each tool has a different affordance — grep finds, awk extracts structure, sed filters ranges, find -exec scales across trees.

Email thread analysis — extract people, dates, commitments, silence

who’s in the thread (@ mentions + From headers)
grep -P '(@\w+|^From:.*<)' comms.adoc
timeline — every date with context
grep -nP '\d{1,2}/\d{1,2}/\d{2,4}|20\d{2}-\d{2}-\d{2}' comms.adoc
commitments — who promised what
grep -niP '(I can |I will |I.ll |we will |we.ll )' comms.adoc
open questions and unknowns
grep -niP '(\?|need to confirm|need to validate|TBD|pending)' comms.adoc

comm — set difference (who hasn’t replied)

# All recipients
grep -oP '<\K[^>]+' comms.adoc | sort -u > /tmp/all-recipients

# All senders
grep -P '^From:' comms.adoc | grep -oP '<\K[^>]+' | sort -u > /tmp/replied

# Who's silent — follow-up targets
comm -23 /tmp/all-recipients /tmp/replied

comm -23 outputs lines only in file 1 (recipients not in senders). Requires sorted input. grep -oP '<\K[^>]+' uses PCRE lookbehind — match < but don’t include it, capture until >.

Sort find results by modification time (newest first)

find discovers files but has no sort. Chain -printf with sort to order by mtime.

awk '{print $2}' truncates filenames with spaces — Familia Romana_ Lingva…​ becomes Familia. Always use the null-safe or sub() variants below for real data.
epoch sort — space-safe (production version)
# Sort by mtime, strip epoch prefix — handles spaces in filenames
find ~/Downloads -maxdepth 1 -name '*.pdf' -printf '%T@ %p\n' | sort -rn | awk '{sub(/^[^ ]+ /,""); print}'

sub(/[ ]+ /,"") removes everything up to and including the first space (the epoch). {print $2} would split on every space — fatal for Familia Romana_ Lingva Latina.

human-readable timestamps alongside
# ISO 8601 timestamps — readable and lexicographically sortable
find ~/Downloads -maxdepth 1 -name '*.pdf' -printf '%T+ %p\n' | sort -r | head -20

%T+ renders YYYY-MM-DD+HH:MM:SS — no epoch math needed, still sorts correctly as text.

null-safe — the bulletproof version
# Null-delimited: survives any filename (newlines, quotes, unicode)
find ~/Downloads -maxdepth 1 -name '*.pdf' -printf '%T@\t%p\0' | sort -zrn | awk -v RS='\0' -F'\t' '{print $2}'

-printf '%T@\t%p\0' — tab separates epoch from path, null terminates. sort -z sorts null-delimited records. awk -v RS='\0' -F'\t' reads null-terminated, splits on tab — $2 is now the full path regardless of spaces.

stat fallback — portable (BSD/macOS)
# GNU stat equivalent — works where -printf is unavailable
find ~/Downloads -maxdepth 1 -name '*latin*' -exec stat --format='%Y %n' {} + | sort -rn | awk '{sub(/^[^ ]+ /,""); print}'

-exec …​ {} + batches all files into one stat call (faster than \;). On macOS, use stat -f '%m %N' instead of --format='%Y %n'.

File intelligence — size, type, duplicates, age

Beyond finding files — interrogating them.

top 10 largest files in a directory tree
# Size in bytes (-printf %s), human-readable via numfmt
find ~/Downloads -type f -printf '%s\t%p\n' | sort -rn | head -10 | numfmt --to=iec --field=1

numfmt --to=iec --field=1 converts the first field from bytes to K/M/G. sort -rn on raw bytes is exact — ls -lhS rounds and sometimes mis-sorts.

find duplicates by size (fast pre-filter before checksumming)
# Files sharing a byte count — likely duplicates (confirm with md5sum)
find ~/Downloads -type f -printf '%s %p\n' | awk '{seen[$1]++; files[$1]=files[$1] "\n  " $0} END {for (s in seen) if (seen[s]>1) print files[s]}'
find duplicates by content — definitive
# md5sum only files with duplicate sizes (two-pass: fast then precise)
find ~/Downloads -type f -printf '%s\n' | sort | uniq -d | while read -r size; do
  find ~/Downloads -type f -size "${size}c" -exec md5sum {} +
done | sort | uniq -w32 -D

Two-pass: first find duplicate sizes (cheap), then md5sum only those (expensive). uniq -w32 -D compares first 32 chars (the hash) and prints all duplicates.

file type census — what’s actually in this directory?
# Count files by MIME type (not extension — extensions lie)
find ~/Downloads -type f -exec file --mime-type -b {} + | sort | uniq -c | sort -rn

file --mime-type -b reports actual content type. -b suppresses filename. A .pdf that’s really text/html is a failed download.

stale files — untouched for 30+ days
# Files not accessed in 30 days — candidates for cleanup
find ~/Downloads -maxdepth 1 -type f -atime +30 -printf '%A+ %s\t%p\n' | sort | numfmt --to=iec --field=2

-atime 30` = access time older than 30 days. `-printf '%A' shows last access. Useful for Downloads cleanup without deleting something you just renamed.

disk usage by subdirectory — sorted
# Which subdirectories consume the most space?
find . -maxdepth 1 -type d -exec du -sh {} + 2>/dev/null | sort -rh | head -20

Batch operations — rename, move, transform

rename all files — strip spaces, lowercase, normalize unicode
# Dry run — show what would change (remove echo to execute)
find ~/Downloads -maxdepth 1 -type f -name '* *' -print0 | while IFS= read -r -d '' f; do
  dir=$(dirname "$f")
  base=$(basename "$f" | tr ' ' '-' | tr '[:upper:]' '[:lower:]')
  echo mv "$f" "$dir/$base"
done

IFS= read -r -d '' — the holy trinity for null-safe filename reading. IFS= prevents whitespace trimming. -r prevents backslash interpretation. -d '' reads until null.

move files by extension into categorized subdirectories
# Sort Downloads chaos into folders by type
find ~/Downloads -maxdepth 1 -type f -print0 | while IFS= read -r -d '' f; do
  ext="${f##*.}"
  case "$ext" in
    pdf|epub)    dest="books" ;;
    jpg|png|svg) dest="images" ;;
    sh|py|rb)    dest="scripts" ;;
    *)           dest="other" ;;
  esac
  mkdir -p ~/Downloads/"$dest"
  echo mv "$f" ~/Downloads/"$dest"/
done

${f##.} — parameter expansion: strip longest match of . from front, leaving only the extension. No basename or awk needed.

batch convert epub → asciidoc (like your Cicero fetch script)
# Convert all epubs in a directory to asciidoc via pandoc
find . -name '*.epub' -type f -exec sh -c '
  for epub; do
    adoc="${epub%.epub}.adoc"
    pandoc -f epub -t asciidoc "$epub" -o "$adoc" \
      && printf "  → %s (%s lines)\n" "$adoc" "$(wc -l < "$adoc")" \
      || printf "  ✗ failed: %s\n" "$epub"
  done
' _ {} +

-exec sh -c '…​' _ {} + — batch mode. _ fills $0 (script name, discarded). All matched files become $1, $2, …​ iterated by for epub. One sh invocation, not one per file.

xargs power patterns

parallel processing — 4 cores
# Checksum all PDFs in parallel (4 processes)
find ~/Downloads -name '*.pdf' -print0 | xargs -0 -P4 md5sum

-P4 runs 4 md5sum processes simultaneously. -print0 | xargs -0 is the null-safe pipeline — no filename can break it.

batched execution — two arguments at a time
# Compare files pairwise with diff
find . -name '*.adoc' -print0 | xargs -0 -n2 diff --brief

-n2 feeds two arguments per invocation. Useful for pairwise comparisons, copy operations (-n2 with cp), or any command taking exactly two args.

placeholder — insert filename at specific position
# Backup every config file: cp <file> <file>.bak
find /etc -maxdepth 1 -name '*.conf' -print0 | xargs -0 -I{} cp {} {}.bak

-I{} replaces {} with each filename. Slower than + batching (one cp per file) but necessary when the filename must appear in a specific position.

Process substitution — diff without temp files

compare two directory listings
# What files exist in study-A but not study-B?
diff <(find data/d000/education/ciceron-study -type f -name '*.adoc' | sort) \
     <(find data/d000/education/latin-study -type f -name '*.adoc' | sort)

<(cmd) creates a file descriptor from command output. diff sees two "files" — no temp files created, no cleanup needed.

compare file counts across directories
# Side-by-side: file type census of two directories
paste <(find dir1 -type f -exec file --mime-type -b {} + | sort | uniq -c | sort -rn) \
      <(find dir2 -type f -exec file --mime-type -b {} + | sort | uniq -c | sort -rn)

awk, sed, jq

awk — field extraction

print second field (whitespace-delimited)
awk '{print $2}' file.txt
custom delimiter — colon-separated (like /etc/passwd)
awk -F: '{print $1, $3}' /etc/passwd
extract JSON code blocks from AsciiDoc
awk '/\[source,json\]/{getline; if ($0 ~ /^----/) {p=1; next}} p && /^----/{p=0; next} p' file.adoc
field extraction with printf formatting
awk '{printf "%-30s %s\n", $1, $2}' file.txt

sed — stream editing

in-place replacement with verify-before/after
# Before
awk 'NR==73' /etc/ssh/sshd_config
# Change
sed -i '73s/#GSSAPIAuthentication no/GSSAPIAuthentication yes/' /etc/ssh/sshd_config
# After
awk 'NR==73' /etc/ssh/sshd_config
extract line range
sed -n '10,20p' file.txt

sed — line-targeted replacement (verify-before / change / verify-after)

the full pattern: locate → validate → change → verify
# 1. LOCATE: find the line number
grep -n 'adoc-pdf' zsh/.zshrc

# 2. VALIDATE: read the exact line before changing
awk 'NR==1760' zsh/.zshrc

# 3. CHANGE: target by line number — only hits that line
sed -i '1760s/alias adoc-pdf=/alias build-adoc=/' zsh/.zshrc

# 4. VERIFY: confirm change AND check for collateral
grep -n 'build-adoc\|adoc-pdf' zsh/.zshrc

Without the line number prefix (1760s/), sed replaces every match in the file — a shotgun. With it, surgical. The line number comes from grep -n.

multi-line verify — check two specific lines at once
awk 'NR==1218 || NR==1760' zsh/.zshrc
range extraction — NR for surgical reads from large files
# grep found the error at line 44164 — read 50 lines of context
awk 'NR>=44160 && NR<=44210' session-dump.adoc

No head | tail chains. No sed -n '44160,44210p'. One awk, two numbers.

grep -oP with \K — value extraction from key-value logs

extract just the value after a key (Perl regex)
# ISE syslog — extract failure reasons
grep -oP 'FailureReason=\K[^,;]+' /var/log/syslog | sort | uniq -c | sort -rn

# ISE — extract MAC addresses
grep -oP 'Calling-Station-ID=\K[0-9A-Fa-f:.-]+' /var/log/syslog | sort -u

# ISE — extract NAS IPs
grep -oP 'NAS-IP-Address=\K[0-9.]+' /var/log/syslog | sort -u

# ISE — extract device names
grep -oP 'NetworkDeviceName=\K[^,;]+' /var/log/syslog | sort -u

\K resets the match start — everything before \K is required context but excluded from output. [^,;]+ captures until the next delimiter. Pipe to sort -u for unique, sort | uniq -c | sort -rn for counted frequency.

pattern: grep -oP 'KEY=\KVALUE_REGEX' | sort pipeline
# Generic form — works for any key=value log format
grep -oP 'FIELD_NAME=\K[^,;]+' logfile | sort | uniq -c | sort -rn | head -20

jq — JSON processing

extract nested fields
curl -s localhost:8080/stats | jq '.stats.total_files'
filter array by property
jq '.results[] | select(.category == "standards")' response.json
transform to TSV for spreadsheets
jq -r '.[] | [.title, .path] | @tsv' response.json | column -t -s $'\t'
GitHub API + jq — commit history by path
gh api "repos/EvanusModestus/domus-captures/commits?path=docs/&per_page=10" |
  jq -r '.[] | "\(.commit.author.date[:10]) \(.sha[:7]) \(.commit.message | split("\n")[0])"'

Shell Patterns

xargs — when the next command reads arguments, not stdin

Next command reads…​ Use

stdin (awk, grep, wc, sort)

pipe directly

arguments (stat, rm, cp, nvim, git add)

xargs

copy today’s files to backup — -I{} placeholder
mkdir -p /tmp/adoc-backup-$(date +%F) && \
  find . -name "*.adoc" -type f -newermt "$(date +%F)" | \
  xargs -I{} cp {} /tmp/adoc-backup-$(date +%F)/
parallel validation — -P4 runs 4 at a time
find .drafts -name "*.adoc" -type f | xargs -P4 -I{} asciidoctor -o /dev/null {}
null-delimited pipeline — safe for filenames with spaces
find . -name "*.adoc" -type f -print0 | xargs -0 wc -l

Process substitution — <(cmd) treats output as a file

compare tracker state: yesterday vs today
diff <(grep '|' partials/trackers/work/adhoc/carryover.adoc | head -20) \
     <(git show HEAD~1:partials/trackers/work/adhoc/carryover.adoc | grep '|' | head -20)
files on disk vs files in nav — drift detection
diff <(find docs/modules/ROOT/pages/projects/chla/mschapv2-migration -name "*.adoc" -type f | sort) \
     <(grep -oP 'mschapv2-migration/[^[]+\.adoc' docs/modules/ROOT/nav.adoc | sort)

Command substitution — embed output as arguments

open most recently modified file in nvim
nvim "$(find data/ -name '*.adoc' -type f -printf '%T@ %p\n' | sort -rn | awk 'NR==1{print $2}')"
line count across a project
wc -l $(find docs/modules/ROOT -path '*mschapv2*' -name '*.adoc' -type f)

Conditional execution — capture, test, act

open matching files only if they exist
files=$(find .drafts -name 'in*' -type f) && [ -n "$files" ] && nvim $files
open files that contain unchecked items
files=$(grep -rl '\[ \]' .drafts/*.adoc) && [ -n "$files" ] && nvim $files
guard with grep -q — only act if pattern matches
grep -q 'TODO\|FIXME\|\[ \]' "$file" && nvim "$file"

Pattern: $(capture)[ -n ] tests non-empty → && only proceeds if true. grep -q is the idempotent guard — run repeatedly, only opens when there’s work.

Decrypt and open — find .age, decrypt, nvim in one shot

files=$(find . -name "*tcp-clock*.age" -type f) && \
  [ -n "$files" ] && echo "$files" | xargs -I{} decrypt-file {} && \
  nvim $(echo "$files" | sed 's/\.age$//')

Pattern: find .age only (never tries plaintext), sed derives the decrypted path, guard prevents empty nvim. Change the glob to match any project.

tee_clean — color on screen, clean text in file

tee_clean() {
  tee >(sed 's/\x1b\[[0-9;]*m//g' > "$1")
}

# Color output on terminal, stripped in file
jq -C '.' data.json | tee_clean output.json
xq -C '.' data.xml | tee_clean output.json

# Wrap a whole block
{
  echo "=== Summary ==="
  jq -C '.[] | .name' data.json
} | tee_clean summary.txt

The >(cmd) is process substitution — tee writes to stdout AND to the subshell pipe. sed strips ANSI escape sequences (\x1b\[[0-9;]*m) before they hit the file.

Dependency check — verify toolchain in one shot

for cmd in asciidoctor asciidoctor-pdf pandoc rouge d2 mmdc age; do
  printf "%-20s %s\n" "$cmd" "$(command -v $cmd >/dev/null 2>&1 && echo 'OK' || echo 'MISSING')"
done

Pattern: command -v checks if binary exists on PATH. >/dev/null 2>&1 suppresses output — we only care about exit code. Swap the tool list for any project’s dependencies.

printf safety — dashes as data, not options

wrong — printf treats --- as invalid option
printf '---\n\n'
right — %s format string treats --- as data
printf '%s\n\n' '---'

Kill stuck SSH sessions

Find established SSH connections
lsof -i TCP -n -P | awk '/ssh.*ESTABLISHED/ {print $2, $9}'
Kill all stuck SSH sessions to a specific host
lsof -i TCP -n -P | awk '/ssh.*kvm-01.*ESTABLISHED/ {print $2}' | sort -u | xargs kill
Kill ALL stuck SSH sessions
lsof -i TCP -n -P | awk '/ssh.*ESTABLISHED/ {print $2}' | sort -u | xargs kill

lsof -i TCP -n -P lists all TCP connections. awk filters for SSH + ESTABLISHED, prints only the PID ($2). sort -u deduplicates (multiple file descriptors per process). xargs kill sends SIGTERM to each.

File Descriptors & Redirection

The three file descriptors

FD Name Purpose

0

stdin

input to the command

1

stdout

normal output (valid results)

2

stderr

error messages

Split stdout and stderr into separate files

find / -name "*.conf" 1>results.txt 2>errors.txt

Suppress errors — 2>/dev/null

find / -name "*.conf" 2>/dev/null

Merge stderr into stdout — 2>&1

command 2>&1 | grep "pattern"

This sends both stdout and stderr through the pipe. Without 2>&1, only stdout reaches grep — errors print to the terminal and bypass the pipeline.

Heredoc patterns

multi-line input to a command
cat <<'EOF'
Line 1
Line 2
EOF
heredoc commit messages (quotes prevent variable expansion)
git commit -m "$(cat <<'EOF'
feat: add new feature

Multi-line description here.
EOF
)"

API & curl/jq

domus-api — Documentation System REST API

start the API server
cd ~/atelier/_projects/personal/domus-api && uv run uvicorn domus_api.main:app --host 0.0.0.0 --port 8080
health check
curl -s localhost:8080/ | jq
full-text search
curl -s 'localhost:8080/search?q=mandiant' | jq
search — extract path, title, match count
curl -s 'localhost:8080/search?q=mandiant' | jq '.results[] | {path, title, match_count}'
list pages by category
curl -s 'localhost:8080/pages?category=standards' | jq
all antora.yml attributes
curl -s localhost:8080/attributes | jq

GitHub API

cross-repo search via GitHub API
gh search code "vault seal" --owner EvanusModestus --json repository,path,textMatches |
  jq '.[] | {repo: .repository.full_name, file: .path, match: .textMatches[].fragment}'
count .adoc files in a repo via API
gh api 'repos/EvanusModestus/domus-captures/git/trees/main?recursive=1' |
  jq '[.tree[] | select(.path | endswith(".adoc"))] | length'

Domus Workflows

Read content from terminal (meeting-ready)

today’s worklog
bat docs/modules/ROOT/pages/2026/04/WRKLOG-$(date +%Y-%m-%d).adoc
current priorities
bat docs/modules/ROOT/partials/trackers/work/priorities/current.adoc
carryover backlog
bat docs/modules/ROOT/partials/trackers/work/adhoc/carryover.adoc
any project summary
bat docs/modules/ROOT/partials/projects/mandiant-remediation/summary.adoc

Search and discovery

find all files related to a topic
grep -rl "MSCHAPv2" docs/modules/ROOT/ --include="*.adoc" | sort
search codex entries
grep -rn "pattern" docs/modules/ROOT/partials/codex/ --include="*.adoc" -B1 -A3
list all worklogs for a month
ls -1 docs/modules/ROOT/pages/2026/04/WRKLOG-*.adoc

Tracker aging — calculate days from origin

how many days since a carryover item started
echo $(( ($(date +%s) - $(date -d "2026-03-09" +%s)) / 86400 ))

Encrypted data access (d001)

view encrypted file without disk write
age --decrypt -i ~/.secrets/.metadata/keys/master.age.key \
  data/d001/projects/mandiant-remediation/findings-status-2026-04-16.adoc.age \
  | bat --language asciidoc
project encryption dashboard
for d in data/d001/projects/*/; do
  total=$(find "$d" -type f | wc -l)
  plain=$(find "$d" -type f ! -name '*.age' ! -name 'README.adoc' ! -name '.gitkeep' ! -name '*.py' | wc -l)
  printf "%-25s %s files  %s plaintext\n" "$(basename "$d")" "$total" "$plain"
done

d000 study builds

batch build all docs for a Quijote chapter range
for d in p1-cap-03{7,8,9}; do
  for f in data/d000/education/quijote-study/notas/$d/*.adoc; do
    d000 build "$d/$(basename "$f" .adoc)" html --variant light-cyan
  done
done
build a single study doc (use unique path fragment)
d000 build p1-cap-038/texto-anotado html --variant light-cyan
d000 build p1-cap-038/texto-anotado pdf --theme light-cyan
batch build PDFs for a chapter range
for d in p1-cap-03{7,8,9}; do
  for f in data/d000/education/quijote-study/notas/$d/*.adoc; do
    d000 build "$d/$(basename "$f" .adoc)" pdf --theme light-cyan
  done
done
open all rendered chapters at once
firefox data/d000/education/quijote-study/notas/p1-cap-03{7,8,9}/output/*.html &
firefox data/d000/education/quijote-study/notas/p1-cap-03{7,8,9}/output/*.pdf &
print chapter PDFs (requires CUPS configured)
lp data/d000/education/quijote-study/notas/p1-cap-03{7,8,9}/output/*.pdf
build LPL logic study (English / Spanish)
d000 build annotated-text pdf --theme light-cyan
d000 build lpl-study/notas/texto-anotado pdf --theme light-cyan
build Cicero study
d000 build de-oratore/libro-i/texto-anotado html --variant light-cyan

Available themes

PDF themes (--theme)
ls ~/atelier/_bibliotheca/domus-asciidoc-build/themes/pdf/ | sed 's/-theme\.yml//'
# base blue burgundy catppuccin creative dark don-quijote green
# learning light-cyan navy operations orange purple reference royal
HTML variants (--variant)
~/atelier/_bibliotheca/domus-asciidoc-build/docinfo/compose.sh --list
# light dark catppuccin royal light-cyan

ISE & Network Ops

ISE ERS API — endpoint CRUD

set credentials (session)
export ISE_HOST="{ise-ip}" ISE_USER="admin" ISE_PASS="$(gopass show -o ise/admin)"
list identity groups
curl -sk "https://$ISE_HOST:{ise-ers-port}/ers/config/identitygroup" \
  -H "Accept: application/json" -u "$ISE_USER:$ISE_PASS" | jq '.SearchResult.resources[].name'
check if endpoint exists by MAC
curl -sk "https://$ISE_HOST:{ise-ers-port}/ers/config/endpoint?filter=mac.EQ.AA:BB:CC:DD:EE:FF" \
  -H "Accept: application/json" -u "$ISE_USER:$ISE_PASS" | jq '.SearchResult.total'

Certificate inspection

view EAP-TLS client cert from local store
openssl x509 -in {cert-dir}/client.pem -text -noout | head -30
check cert expiry
openssl x509 -in {cert-dir}/client.pem -enddate -noout

Network diagnostics

check listening ports
ss -tlnp | grep -E ':{port-https}|:{port-ssh}|:{port-ldaps}'
test ISE connectivity
nc -zv {ise-ip} {ise-ers-port}
DNS resolution
dig {ise-hostname} +short

ISE eval rotation — backup & restore

backup from ISE CLI (when admin UI is license-locked)
# SSH to ISE
ssh admin@ise-02.inside.domusdigitalis.dev

# Verify NAS repo
show repository nas-01

# Get encryption key (on workstation)
dsource d000 dev/storage
echo $ISE_BACKUP_KEY

# Run backup
backup pre-rotation-2026-06 repository nas-01 ise-config encryption-key plain <KEY>
list backups on NAS
ssh admin@ise-02.inside.domusdigitalis.dev
show repository nas-01
restore to fresh ISE node
configure terminal
repository nas-01
  url nfs://10.50.1.70:/volume1/ise_backups
exit

restore <backup-filename> repository nas-01 encryption-key plain <KEY>

VyOS — VRRP & VLAN inspection

VRRP status and VIPs
show vrrp
show configuration commands | grep vrrp | grep 'address'
firewall zone membership
show configuration commands | grep 'firewall zone' | grep 'member'
DHCP leases and ARP
show dhcp server leases
show arp
full interface/VLAN map
show interfaces

CUPS printing — validation & setup

software validation
command -v lpstat && echo "CUPS present" || echo "CUPS not installed"
lpstat -r                                # scheduler running?
lpstat -p -d                             # printers + default
daemon lifecycle
sudo systemctl enable --now cups         # start + persist
printer discovery
lpinfo -v                                # available backends/URIs
lpinfo -m | grep -i <brand>             # available drivers
add printer and set default
sudo lpadmin -p <name> -v <uri> -m everywhere -E
lpoptions -d <name>
print
lp file.pdf                              # default printer
lp -d <name> -o sides=two-sided-long-edge file.pdf

PowerShell (from zsh)

All PowerShell commands run inside pwsh -NoLogo -Command '…​' from zsh. Running them bare fails — zsh interprets $, |, () as shell syntax.

Process management

top 5 processes by memory
pwsh -NoLogo -Command 'Get-Process | Sort-Object WorkingSet64 -Descending |
  Select-Object -First 5 ProcessName, Id,
    @{N="MB";E={[math]::Round($_.WorkingSet64/1MB)}} | Format-Table'
stop/start Teams
pwsh -NoLogo -Command 'Get-Process | Where-Object {$_.ProcessName -like "*teams*"} | Stop-Process'
pwsh -NoLogo -Command 'Start-Process "ms-teams"'

Export to JSON (pipe to jq)

always use -NoLogo when piping pwsh output to zsh tools
pwsh -NoLogo -Command 'Get-Process | Sort-Object WorkingSet64 -Descending |
  Select-Object -First 5 ProcessName, Id,
    @{N="MB";E={[math]::Round($_.WorkingSet64/1MB)}} | ConvertTo-Json' | jq '.'
Never pipe Format-Table into ConvertTo-Json — it produces layout metadata, not data. Select-Object first, then ConvertTo-Json.

Wi-Fi management (netsh)

force fresh network scan
netsh wlan disconnect interface="Wi-Fi"
netsh wlan show networks mode=bssid
netsh wlan connect name="CHLA-Remote" interface="Wi-Fi"

SSH from PowerShell

connect to homelab from Windows terminal
ssh evan@modestus-razer.inside.domusdigitalis.dev

WSL ↔ Windows — Cross-Environment Commands

From zsh (WSL) — control Windows
run any PowerShell command from zsh
pwsh -NoLogo -Command 'Get-Date'
run multi-line PowerShell from zsh (heredoc)
pwsh -NoLogo -Command "$(cat <<'PS'
$procs = Get-Process | Where-Object { $_.WorkingSet64 -gt 100MB }
$procs | Sort-Object WorkingSet64 -Descending |
  Select-Object ProcessName, Id, @{N="MB";E={[math]::Round($_.WorkingSet64/1MB)}} |
  Format-Table -AutoSize
PS
)"
open a file in Windows from WSL
# Open in default Windows app
wslview /mnt/c/Users/erosado/Documents/report.pdf

# Open Explorer to current WSL directory
explorer.exe .

# Open specific Windows path
explorer.exe 'C:\Users\erosado\Downloads'
copy WSL output to Windows clipboard
# Pipe anything to Windows clipboard
cat file.txt | clip.exe

# Copy a command's output
pwsh -NoLogo -Command 'Get-TransportRule | Format-List Name, State' | clip.exe
access Windows files from WSL
# Windows C: drive is at /mnt/c
ls /mnt/c/Users/erosado/Downloads/

# Copy from Windows to WSL
cp /mnt/c/Users/erosado/Downloads/report.pdf ~/atelier/

# Watch a Windows directory for new files
find /mnt/c/Users/erosado/Downloads -maxdepth 1 -mmin -5 -type f -printf '%T+ %p\n' | sort -r
From PowerShell — control WSL
run a bash command from PowerShell
wsl -e bash -c 'grep -rn "Ghost-Sender" ~/atelier/_bibliotheca/domus-captures/docs/'
run a specific WSL command and capture output
$result = wsl -e bash -c 'git -C ~/atelier/_bibliotheca/domus-captures log --oneline -5'
$result
Process Management — Windows Side
top processes by memory — formatted table
pwsh -NoLogo -Command '
Get-Process | Sort-Object WorkingSet64 -Descending |
  Select-Object -First 20 ProcessName, Id,
    @{N="MB";E={[math]::Round($_.WorkingSet64/1MB)}},
    @{N="CPU(s)";E={[math]::Round($_.CPU,1)}},
    @{N="Handles";E={$_.HandleCount}} |
  Format-Table -AutoSize'
find a specific process
pwsh -NoLogo -Command 'Get-Process | Where-Object { $_.ProcessName -like "*teams*" } |
  Select-Object ProcessName, Id, @{N="MB";E={[math]::Round($_.WorkingSet64/1MB)}} |
  Format-Table -AutoSize'
kill by name
pwsh -NoLogo -Command 'Stop-Process -Name "Teams" -Force -ErrorAction SilentlyContinue'
kill by PID
pwsh -NoLogo -Command 'Stop-Process -Id 12345 -Force'
what’s listening on a port (Windows equivalent of ss -tulnp)
pwsh -NoLogo -Command 'Get-NetTCPConnection -State Listen |
  Select-Object LocalAddress, LocalPort, OwningProcess,
    @{N="Process";E={(Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).ProcessName}} |
  Sort-Object LocalPort | Format-Table -AutoSize'
specific port check
pwsh -NoLogo -Command 'Get-NetTCPConnection -LocalPort 8080 -ErrorAction SilentlyContinue |
  Select-Object LocalAddress, LocalPort, RemoteAddress, State,
    @{N="Process";E={(Get-Process -Id $_.OwningProcess).ProcessName}}'
Services — Windows Side
list running services
pwsh -NoLogo -Command 'Get-Service | Where-Object { $_.Status -eq "Running" } |
  Sort-Object DisplayName | Format-Table Name, DisplayName, Status -AutoSize'
check a specific service
pwsh -NoLogo -Command 'Get-Service -Name "WinRM" | Format-List Name, DisplayName, Status, StartType'
restart a service
Restart-Service -Name "WinRM" -Force
System Info — Quick Health from zsh
one-shot Windows system summary
pwsh -NoLogo -Command '
Write-Host "=== Windows System ===" -ForegroundColor Cyan
Write-Host "Hostname: $env:COMPUTERNAME"
Write-Host "User:     $env:USERNAME"
Write-Host "OS:       $((Get-CimInstance Win32_OperatingSystem).Caption)"
Write-Host "Uptime:   $((Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime)"
Write-Host "RAM:      $([math]::Round((Get-CimInstance Win32_OperatingSystem).TotalVisibleMemorySize/1MB))GB total, $([math]::Round((Get-CimInstance Win32_OperatingSystem).FreePhysicalMemory/1MB))GB free"
Write-Host "CPU:      $((Get-CimInstance Win32_Processor).Name)"
Write-Host "Disk C:   $([math]::Round((Get-PSDrive C).Free/1GB))GB free of $([math]::Round(((Get-PSDrive C).Used + (Get-PSDrive C).Free)/1GB))GB"'
disk usage — all drives
pwsh -NoLogo -Command 'Get-PSDrive -PSProvider FileSystem |
  Select-Object Name, @{N="Used(GB)";E={[math]::Round($_.Used/1GB,1)}},
    @{N="Free(GB)";E={[math]::Round($_.Free/1GB,1)}},
    @{N="Total(GB)";E={[math]::Round(($_.Used+$_.Free)/1GB,1)}} |
  Format-Table -AutoSize'
Exchange Online — Connect from zsh
connect to Exchange Online (launches MFA prompt in Windows)
pwsh -NoLogo -Command 'Connect-ExchangeOnline -UserPrincipalName erosado@chla.usc.edu'
MFA prompt opens in the Windows browser. After auth, the session persists in the pwsh process. For multi-command sessions, start pwsh interactively instead of one-shot commands.
interactive PowerShell session from zsh (for Exchange, etc.)
pwsh -NoLogo
# Then inside pwsh:
# Connect-ExchangeOnline
# Get-TransportRule | Format-List Name, State
# exit
File Transfer Patterns
move files between WSL and Windows
# WSL → Windows Downloads
cp ~/atelier/_bibliotheca/domus-captures/output/report.pdf /mnt/c/Users/erosado/Downloads/

# Windows → WSL (glob)
cp /mnt/c/Users/erosado/Downloads/*.{png,pdf,jpg} ~/atelier/_staging/

# Bulk move with null safety
find /mnt/c/Users/erosado/Downloads -maxdepth 1 -name '*.pdf' -mmin -60 -print0 |
  xargs -0 -I{} cp {} ~/atelier/_staging/
watch Windows Downloads for new files (live)
inotifywait -m /mnt/c/Users/erosado/Downloads -e create -e moved_to |
  awk '{printf "%s  %s\n", strftime("%H:%M:%S"), $3}'
inotifywait requires inotify-tools. Install with sudo pacman -S inotify-tools if not present.

Security & Encryption

View encrypted files without writing to disk

pipe age decrypt to bat — nothing touches the filesystem
age --decrypt -i ~/.secrets/.metadata/keys/master.age.key \
  data/d001/projects/mandiant-remediation/findings-status-2026-04-16.adoc.age \
  | bat --language asciidoc --file-name "findings-status-2026-04-16.adoc"

Batch re-encrypt — brace expansion + loop

re-encrypt multiple project files
for f in data/d001/projects/mandiant-remediation/{findings-status,guest-acl-update,siem-report}-2026-04-16.adoc; do
  rm -f "${f}.age" && echo y | encrypt-file "$f"
done
Always rm -f the .age first. If you skip it, encrypt-file prompts about overwrite and may only delete the plaintext without re-encrypting.

Detect stale plaintext — files needing re-encryption

find plaintext newer than its .age counterpart
for f in data/d001/projects/*/*.adoc; do
  age="${f}.age"
  if [ -f "$f" ] && [ -f "$age" ]; then
    pt_mod=$(/usr/bin/stat -c'%Y' "$f")
    age_mod=$(/usr/bin/stat -c'%Y' "$age")
    [ "$pt_mod" -gt "$age_mod" ] && echo "STALE: $f"
  fi
done

Secure delete — shred for sensitive plaintext

shred -u data/d001/projects/mandiant-remediation/man-report.txt
On SSD/NVMe, shred is less effective (wear leveling), but better than rm which only removes the directory entry.

Pre-push audit — find all unencrypted project files

find data/d001/projects -type f ! -name '*.age' ! -name 'README.adoc' ! -name '.gitkeep' ! -name '*.py' | sort

System & Infrastructure

PipeWire audio validation

wpctl status                                    # PipeWire status
pactl list sinks short                          # list audio sinks
pw-play /usr/share/sounds/freedesktop/stereo/bell.oga  # test default sink
journalctl -b --grep='sof|cs35l56' --no-pager | tail -20  # kernel audio firmware
cat /proc/asound/cards                          # ALSA sound cards

gopass — personal document management

gopass-personal-docs    # interactive entry creation
gopass-query bills      # list recurring bills with totals
gopass-query storage    # list storage units with gate codes
gopass-query export bills  # export category to JSON

Makefile — daily workflow

make new-day      # create today's worklog + update attributes
make serve        # build + local server (port 8000)
make              # build only
make sync-nav     # sync worklog nav entries
make update-index # rebuild monthly index

KVM — VM & ISO management

list VMs on a KVM host
ssh kvm-01 "sudo virsh list --all"
ssh kvm-02 "sudo virsh list --all"
find ISE ISOs across KVM hosts (case-insensitive glob)
ssh kvm-01 "ls -lh /mnt/nas/isos/*[Ii][Ss][Ee]* /var/lib/libvirt/images/*[Ii][Ss][Ee]* /mnt/onboard-ssd/isos/*[Ii][Ss][Ee]* 2>/dev/null"
ssh kvm-02 "ls -lh /mnt/nas/isos/*[Ii][Ss][Ee]* /mnt/ssd/libvirt/images/*[Ii][Ss][Ee]* 2>/dev/null"
console into a VM
sudo virsh console <vm-name>             # Escape: Ctrl+]
check NAS mount on KVM host
ssh kvm-01 "mount | grep nas; ls /mnt/"

Per-project file dashboard

per-project summary — total files vs unencrypted plaintext
for d in data/d001/projects/*/; do
  total=$(find "$d" -type f | wc -l)
  plain=$(find "$d" -type f ! -name '*.age' ! -name 'README.adoc' ! -name '.gitkeep' ! -name '*.py' | wc -l)
  echo "$(basename "$d") | ${total} files | ${plain} plaintext"
done

USB-C / Thunderbolt Charging Diagnostics

Full evidence capture to file (one block, timestamped)
{
  echo "=== Power Supply ==="
  cat /sys/class/power_supply/*/status
  echo ""
  cat /sys/class/power_supply/*/type
  echo ""
  echo "=== UPower ==="
  upower -d | grep -E 'state|percentage|energy-rate|voltage'
  echo ""
  echo "=== dmesg (typec/thunderbolt/PD) ==="
  sudo dmesg | grep -iE 'typec|thunderbolt|ucsi|PD|power.delivery|charging' | tail -20
  echo ""
  echo "=== Pacman log (kernel/typec) ==="
  grep -iE 'thunderbolt|typec|ucsi|^.*upgraded linux ' /var/log/pacman.log | tail -20
} | tee /tmp/INC-$(date +%F)-usbc-charging.txt

Pattern: { } groups commands into a single stdout stream. tee writes to file AND displays on screen. Reusable for any multi-command evidence capture — change the commands inside, keep the structure.

pacman — package inspection

Source: 2026-06-25 — curl error 77 investigation, checking for package upgrades

# Check package version and install date (awk field filter)
pacman -Qi curl | awk '/^Version|^Install Date/'