*Published August 13, 2026*
---
*Part two of a three-part set on how I work with agents day to day. Part one: [Nine Security Issues, Zero Lines I Wrote](https://para.ngpcloud.org/nine-security-issues-zero-lines-i-wrote). Part three: The Ledger That Stayed Empty.*
---
## TL;DR
I maintain more repos than I can check by hand. A small system called portfolio-ops watches all of them, runs one deterministic scan, and turns whatever it finds into one of three narrow requests. The pipeline from [the other piece](https://para.ngpcloud.org/nine-security-issues-zero-lines-i-wrote) only ever handles one of those three: turning a specific issue into a specific PR.
Deciding what's worth fixing and actually fixing it turned out to need two separate systems.
---
## The Problem Underneath the Pipeline
The pipeline from the other piece is good at one thing: given a specific GitHub issue on a specific repo, turn it into a reviewed, correct pull request without me touching the keyboard. It has no opinion about *which* issue, or *which* repo.
Somebody still has to notice a security review went stale, a dependency PR has sat for three weeks, or an old pull request to somebody else's repo went dead because they emptied the repository and nothing told me. That somebody was me, doing it badly, because checking ten repos by hand is the first task that gets skipped when the week gets busy.
Portfolio-ops is the somebody. It's a catalog file listing every repo I actually care about, tagged by tier (CLI tool, org hub, public site). A script walks that list, plus a separate global query for pull requests I've opened against repos outside it, and reports only what needs a decision.
None of this replaces Dependabot or GitHub's Security tab. Neither tracks a PR I've opened against someone else's repo, and neither watches for a scanner failing to see its own output. Dependabot's own pull requests still show up in the scan, though, routed through the same triage as everything else.
---
## One Scan, Three Kinds of Decision
The scan is boring on purpose. It runs the same deterministic pass every time, not an agent improvising a check, so "no findings" always means the same thing. It looks for open pull requests sitting on each repo, security issues past SLA, whether a repo's CI actually runs a vulnerability scan, and pull requests I've personally opened against other people's repos, since those don't show up in any catalog I own.
Whatever it finds gets triaged into exactly one of three requests. The runbook is explicit. These are the only three shapes a request can take.
- **Work an issue into a PR.** Hand it to the full pipeline, respect the cap of two running at once, get back a merge-ready pull request.
- **Clear a slice of stuck pull requests.** Existing PRs, mine or Dependabot's, get pushed through review in small batches, capped at three per session, until there's a clean merge list.
- **Investigate a repo from scratch.** No fix attempt, just a written security pass that ends in either filed findings or an explicit "clean, here's how I checked."
Everything portfolio-ops does routes through one of those three. It never freelances a fourth, and it doesn't touch code. It only decides what gets *asked for*.
---
## Two Things the Scan Caught
- **The 102-day pull request.** The scan flagged a pull request I'd opened against someone else's repo 102 days ago. The directory my PR targeted had been emptied out, nothing left to merge into. The fix was closing the PR with an explanation. I hadn't looked at that PR since I opened it. The scan is the only reason it got closed instead of sitting open indefinitely.
- **The scanner's blind spot in its own output.** Security-pass issues get filed with a `sec:` title prefix. The scan's own SLA check matched on issue *labels*, not that prefix, so the scanner couldn't see its own output: [the nine issues feeding the pipeline](https://github.com/ph-commons/nowshowing-pp-cli/issues/6) were briefly invisible to the system meant to track them. Fixed by adding a title-prefix check the SLA scan never had. The SLA check now matches on the `sec:` prefix as well as the label.
---
## The Guardrails
Both systems will run more work in parallel than I want reviewed at once. Without caps, nothing stops an agent from kicking off nine pipeline runs simultaneously, and nine PRs landing together is nine PRs I have to read carefully in one sitting. The caps, two pipeline runs at a time, three PRs per review pass, one repo per investigation, exist to pace how much unreviewed output I'll have in flight.
One rule stayed non-negotiable. The catalog that tracks repos and the ledger that tracks my commitments to other people never touch. Nothing in portfolio state becomes a promise to a person. That boundary keeps the ledger honest, because everything in it is something a person is actually owed.
Portfolio-ops found the nine issues and put them in front of me. The pipeline did the fixing, catching real bugs along the way. The scan doesn't write code; the pipeline doesn't decide what's worth its attention. I sit at both ends: deciding what gets triaged, pressing merge on what comes back clean.