WCAG 2.1 AA audit — perceivable, operable, understandable, robust criteria. Deep-dive for /launch-check accessibility.
The English summary is being prepared. Showing the original description.
Show every item across managed projects needing the user's attention — PRs, assigned issues, comments, blockers.
The English summary is being prepared. Showing the original description.
Run score Not tested
See how to installReview the instructions the agent will receive before you install.
Writing: read docs/skills/shared/writing-rule.md before you write a durable artifact.
Aggregates everything that's currently waiting on you across the projects ApexYard manages. Designed to be the first thing you run in a session.
Read the registry path via portfolio_registry, the per-project docs dir via portfolio_projects_dir, and the ideas backlog via portfolio_ideas_backlog — all from .claude/hooks/_lib-portfolio-paths.sh. Source the helper at the top of any bash block that touches those paths:
source "$(git rev-parse --show-toplevel)/.claude/hooks/_lib-read-config.sh"
source "$(git rev-parse --show-toplevel)/.claude/hooks/_lib-portfolio-paths.sh"
source "$(git rev-parse --show-toplevel)/.claude/hooks/_lib-tracker.sh"
registry=$(portfolio_registry)
Defaults match today's single-fork layout (./apexyard.projects.yaml, ./projects, ./projects/ideas-backlog.md). Adopters in split-portfolio mode override the portfolio.{registry, projects_dir, ideas_backlog} keys in .claude/project-config.json. Don't hardcode literal apexyard.projects.yaml or projects/ paths in bash blocks — the helper resolves whichever mode the adopter is in. See docs/multi-project.md.
The issue sections below (assigned to you, your issues with new comments, blocked items) call tracker_list from _lib-tracker.sh instead of hardcoding gh issue list, so they work on a project whose tracker.kind is glab (GitLab) too. Pass the project's repo: (from the registry) as the first argument — the tracker is resolved per-project — plus generic filters:
# tracker_list <owner/repo> [state=…] [assignee=@me|none|<user>] [author=…] [labels=csv] [search=…] [since=ISO] [limit=N]
# → emits a JSON array: [{ref,number,state,title,url,labels,updatedAt}, …] ([] on empty/unavailable)
tracker_list "$repo" state=open assignee=@me limit=50 2>/dev/null
Check that each read was complete (#1441). tracker_list prints [] and returns non-zero on
failure, and a result that fills the limit may be a short read. Use tracker_list_to, which writes
the array to a file and returns the verdict on stdout:
tmp=$(mktemp) || return 1
status=$(tracker_list_to "$tmp" "$repo" state=open assignee=@me limit=50 2>/dev/null); rc=$?
if [ "$status" = "TRUNCATED" ]; then
status=$(tracker_list_to "$tmp" "$repo" state=open assignee=@me limit=200 2>/dev/null); rc=$?
fi
case "$status" in
UNKNOWN)
if [ "$rc" -ne 0 ]; then
echo "$repo: could not read issues" # a failure, never print 0
else
echo "$repo: read $(jq -r 'length' < "$tmp"), completeness unknown"
fi ;;
TRUNCATED) echo "$repo: at least $(jq -r 'length' < "$tmp") issues" ;; # still not the end
esac
items=$(cat "$tmp"); rm -f "$tmp"
UNKNOWN means two different things, and the exit status tells them apart. A non-zero status
is a failed read, so report it as unread. A zero status with UNKNOWN is a successful read whose
completeness this library cannot judge: a custom adapter called with no limit, or a payload it
cannot count. The rows are good. Only the "is that all of them" answer is missing.
Do not write items=$(tracker_list …) and then read TRACKER_LIST_STATUS. Command
substitution runs the call in a subshell, so the variable never reaches you, and a stale verdict
from an earlier project reads as this project's. That turns a failed read into a confident zero,
which is the failure this check exists to prevent. TRACKER_LIST_STATUS is correct only for a call
made in the current shell.
On UNKNOWN, say the count is unknown for that project. Do not fold it into a zero. GitLab caps a
page at 100, so a glab project stays TRUNCATED there.
Scope caveat (forge axis, #711). The PR sections still call
gh pr listdirectly. The PR/MR forge abstraction is a separate ticket (#711); until it lands,/inbox's PR sections are GitHub-only./inboxis therefore issue-axis tracker-agnostic, not fully tracker-agnostic. Filters GitHub expresses but GitLab can't (mentions:,commenter:) stay on a gh-only path, documented at the section that uses them.
/inbox
/inbox --me octocat
/inbox --since 24h
/inbox iterates every project in apexyard.projects.yaml at the root of your ops repo (your fork of apexyard). If the registry doesn't exist, print a clear error pointing at docs/multi-project.md.
The inbox is grouped by section. Empty sections are omitted.
Forge axis (#711) — GitHub-only until the PR/MR abstraction lands.
gh pr list \
--search "is:open is:pr review-requested:@me" \
--json number,title,url,headRepository,updatedAt,author \
--limit 50
Run this per repo: from the registry (or use --search "user:your-org" if you have an org).
gh pr list \
--search "is:open is:pr author:@me review:changes_requested" \
--json number,title,url
These are blocking you, not your reviewers — they're your inbox.
gh pr list \
--search "is:open is:pr author:@me review:approved" \
--json number,title,url,mergeable,mergeStateStatus
Filter to ones where mergeStateStatus is CLEAN — those are ready to merge right now.
Issue axis — tracker-agnostic via tracker_list (run per repo: from the registry):
tracker_list "$repo" state=open assignee=@me limit=50
# → [{ref,number,state,title,url,labels,updatedAt}, …]
The "new comments since last looked" part is a GitHub-only search qualifier (commenter:>@me) with no GitLab equivalent, so tracker_list fetches your open-authored issues and the comment recency is filtered client-side (the established degradation for no-equivalent filters):
tracker_list "$repo" state=open author=@me
# Then filter client-side on `updatedAt` against a stored "last seen" timestamp
# if available, otherwise show everything from the last 7 days.
mentions:@me is a cross-repo GitHub-search capability (a different operation than a repo-scoped list) with no GitLab CLI equivalent, so this section stays on a gh-only path — it returns nothing on non-GitHub trackers, and --no-mentions hides it entirely:
# gh-only (degrades to empty on glab / other trackers):
if [ "$(tracker_kind "$repo")" = "gh" ]; then
gh search issues "mentions:@me is:open" \
--json number,title,url,repository,updatedAt
fi
Forge axis (#711) — GitHub-only until the PR/MR abstraction lands.
gh pr list \
--search "is:open is:pr author:@me" \
--json number,title,url,statusCheckRollup
Filter client-side to those where any check is FAILURE.
Issue axis — tracker-agnostic via tracker_list (run per project from the registry):
tracker_list "$repo" state=open labels=blocked
Forge axis (#711) — GitHub-only until the PR/MR abstraction lands.
The sibling of the reconcile-before-build rule: that rule stops NEW drift at the spawn boundary; this section surfaces EXISTING drift that already happened. The signature is cheap and mechanical — an issue that is still OPEN but a merged PR already references it (Closes #N that didn't fire because the PR merged to dev, not the release branch; or Refs #N left open on purpose for a QA gate).
Fetch once per repo, not once per open issue — a batched query is the whole point, both for gh rate limits and for wall-clock time across a portfolio:
# 1. Open issue numbers for this repo (one call).
open_issues=$(gh issue list --repo "$repo" --state open --json number --jq '.[].number')
# 2. Merged PRs for this repo, bounded so the scan stays cheap (one call).
# --limit 200 is a reasonable default; tighten it further with --search
# "merged:>=<since-date>" on a very active repo, or when --since is passed.
gh pr list --repo "$repo" --state merged \
--json number,title,body,url,mergedAt --limit 200
Then, for each merged PR's title + body, extract issue references and classify them:
close[sd]?, fix(e[sd])?, resolve[sd]? immediately followed by #N (case-insensitive). A match here against an issue still open is very likely a release-cut artifact — the PR's Closes #N didn't auto-fire because it merged to a non-default branch.refs?, references?, related to immediately followed by #N. A match here is likely an intentional QA gate — the ticket is deliberately held open pending verification (see workflows/sdlc.md Phase 5) — surface it as lower-urgency than a closing-keyword match.Conservative by construction: only count a reference when a closing/referencing keyword sits directly next to the #N (not any bare number appearing anywhere in a PR body) AND N is in the open_issues set fetched in step 1. A PR that happens to mention an unrelated number, or a #N for an issue that's already closed, produces no flag. This is what keeps the section from ever flagging a genuinely-open or gated ticket.
Graceful degradation: if either gh call fails for a repo (rate limit, auth, network), skip that repo's contribution to this section and continue — same as Rule 5 below. If a repo produces zero matches, the section is simply absent for it (Rule 4).
Group everything under headings, project-prefixed:
INBOX — 2026-04-06 09:14
=========================
🔴 PRs awaiting your review (3)
· example-app#42 Add export to CSV updated 1h ago https://…
· billing-api#8 Fix invoice rounding updated 3h ago https://…
· marketing#12 Hero copy refresh updated 1d ago https://…
🟡 Your PRs with changes requested (1)
· example-app#39 Refactor session store Code Reviewer requested changes https://…
🟢 Your PRs ready to merge (1)
· example-app#41 Add health endpoint 2 approvals · CI green https://…
📬 Issues assigned to you (4)
· example-app#117 [Bug] Login fails on Safari priority-high https://…
· billing-api#22 [Feature] Multi-currency support priority-medium https://…
· …
💬 New comments on issues you opened (2)
· example-app#98 3 new comments since yesterday https://…
· marketing#5 Designer left a comment https://…
🚨 PRs with failing CI (1)
· example-app#42 lint job failed https://…
🛑 Blocked items (1)
· billing-api#19 Waiting on API key from vendor https://…
🔁 Reconcile — open issues with a merged PR (2)
· example-app#88 Closes-but-open · merged PR #101 (release-cut?) https://…
· billing-api#31 Refs-open · merged PR #64 (QA gate?) https://…
Summary: 12 items · 3 PRs to review · 1 ready to merge · 1 blocking CI failure · 2 to reconcile
If everything is empty:
✨ Inbox zero. Nothing waiting on you across {N} projects.
| Flag | Effect |
|---|---|
--me <user> | Run as if <user> is the current user (default: @me) |
--since <duration> | Only items updated in the window (e.g. 24h, 7d) |
--project <name> | Limit to one project from the registry |
--no-mentions | Hide the mentions section |
--no-reconcile | Hide the Reconcile section (#923) |
apexyard.projects.yaml count; never shell out to "all repos in the org"(0)? and continue/tasks — same data but flattened into a single ordered TODO list/status — current project's git/CI snapshot/projects — portfolio-level health snapshotPart of ApexYard — multi-project SDLC framework for Claude Code · MIT.
No reviews yet. Tell others what you thought.
No login needed. Share how it worked for you, ask a question, or note where it did not run.
No comments yet. Be the first to write one.
WCAG 2.1 AA audit — perceivable, operable, understandable, robust criteria. Deep-dive for /launch-check accessibility.
The English summary is being prepared. Showing the original description.
WCAG 2.2 AA audit — perceivable, operable, understandable, robust criteria. Deep-dive for /launch-check accessibility.
The English summary is being prepared. Showing the original description.
Browse / search / show / stats AgDRs across the portfolio — recalls "have we decided this before?".
The English summary is being prepared. Showing the original description.
Analytics audit — SDK config, event naming, funnel completeness, dashboards. Deep-dive for /launch-check analytics.
The English summary is being prepared. Showing the original description.
Record per-PR architecture-review approval for design-artifact PRs (required by the architecture gate). ONLY on an explicit per-PR architect "approved".
The English summary is being prepared. Showing the original description.
Record per-PR design-review approval (UI merge gate). ONLY on an explicit per-PR designer "approved".
The English summary is being prepared. Showing the original description.