WCAG 2.1 AA audit — perceivable, operable, understandable, robust criteria. Deep-dive for /launch-check accessibility.
日本語の概要は準備中です。原文の説明を表示しています。
Show every item across managed projects needing the user's attention — PRs, assigned issues, comments, blockers.
日本語の概要は準備中です。原文の説明を表示しています。
実行スコア 未検証
インストール方法を見るインストールする前に、エージェントに与えられる指示の中身を確認できます。
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.
まだレビューはありません。使ってみた感想をお寄せください。
ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。
まだコメントはありません。最初のコメントを書いてみませんか。
WCAG 2.1 AA audit — perceivable, operable, understandable, robust criteria. Deep-dive for /launch-check accessibility.
日本語の概要は準備中です。原文の説明を表示しています。
WCAG 2.2 AA audit — perceivable, operable, understandable, robust criteria. Deep-dive for /launch-check accessibility.
日本語の概要は準備中です。原文の説明を表示しています。
Browse / search / show / stats AgDRs across the portfolio — recalls "have we decided this before?".
日本語の概要は準備中です。原文の説明を表示しています。
Analytics audit — SDK config, event naming, funnel completeness, dashboards. Deep-dive for /launch-check analytics.
日本語の概要は準備中です。原文の説明を表示しています。
Record per-PR architecture-review approval for design-artifact PRs (required by the architecture gate). ONLY on an explicit per-PR architect "approved".
日本語の概要は準備中です。原文の説明を表示しています。
Record per-PR design-review approval (UI merge gate). ONLY on an explicit per-PR designer "approved".
日本語の概要は準備中です。原文の説明を表示しています。