agentsclimarketplace

Landscape

Skill flurdy/agent-skills/skills/landscape

Shared AI agent skills

Install
npx -y skills add flurdy/agent-skills --skill landscape

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 6 stars6 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Morning catch-up view β€” assigned Jira tickets and recent discussion, open PRs, current working copy state, and (if present) in-progress and ready beads in one glance. Run at session start to orient.

SKILL.md

21.3 KB, as published. Nobody here has run it

Landscape β€” Morning Catch-up

Show a consolidated landscape of where you are and what to do next, pulling from multiple sources at once. Designed for the start of a work session (especially Monday mornings) to quickly orient.

Usage

/landscape          # Full landscape
/landscape quick    # Skip PR details (faster, Jira + working-copy + beads-if-present only)

What It Shows

Separate blocks, rendered from broadest context to most immediate. Order matters β€” the last block is the most load-bearing for "what am I doing right now":

  1. πŸ“‹ Jira β€” tickets assigned to you, not Done (with sprint and latest discussion)
  2. πŸ”€ PRs β€” org-wide open PRs, recently closed, unresolved threads
  3. 🎯 Beads β€” in-progress and top ready beads in this repo (skipped if bd not installed)
  4. πŸ“ Working copy β€” current branch, uncommitted/unpushed work (plus, in a multi-repo workspace, a roll-up of sibling service repos with unsaved/unpushed state)
  5. Next β€” single-sentence suggestion for the most load-bearing action

Each block is independent β€” if one source fails, the others still render.

Instructions

MUST re-fetch on every invocation. Each /landscape run MUST execute every fetch from scratch β€” date, the Jira MCP query, the gh-pr-list-* and gh-pr-details.sh scripts, beads.sh, and working-copy.sh. NEVER reuse output from a previous run in the same session and NEVER extrapolate timestamps. State changes (PR merges, new approvals, ticket transitions) happen between runs; reusing stale tables has caused real merges to be missed in /pr-status and the same risk applies here.

MUST use the dedicated helper scripts. Never construct ad-hoc bd … or git … shell pipelines for this skill. Specifically: do NOT chain command -v bd probes with bd list … && … or … || bd list --ready inside a single Bash call. Always invoke ~/.agents/skills/landscape/scripts/beads.sh instead β€” it handles probing, repo gating, and listing internally. Likewise, do NOT hand-walk sibling service repos with your own for … git -C … loop β€” always go through ~/.agents/skills/wrap-up/scripts/multirepo.sh (Β§4b), which handles workspace detection and per-repo state. Inline chaining bypasses the per-script permission allowlist and produces noisy permission prompts.

Render the blocks in the order listed below. Some data fetches can run in parallel at the top.

0. Header

date '+%A %Y-%m-%d %H:%M'

Output:

## Landscape β€” {Weekday} {YYYY-MM-DD} {HH:MM}

If the weekday is Monday, add a subtitle: _Monday β€” extra catch-up across the weekend._

1. πŸ“‹ Jira β€” assigned to you

Query Jira for open tickets assigned to the current user, including sprint membership. The sprint field is the Jira Cloud default custom field customfield_10020. Use the MCP tool:

mcp__jira__jira_get
  path: /rest/api/3/search/jql
  queryParams:
    jql: assignee = currentUser() AND statusCategory != Done ORDER BY cf[10020] ASC, priority DESC, updated DESC
    fields: summary,status,priority,issuetype,updated,customfield_10020
    maxResults: 20
  jq: issues[*].{key: key, summary: fields.summary, type: fields.issuetype.name, status: fields.status.name, priority: fields.priority.name, updated: fields.updated, sprint: fields.customfield_10020}

The sprint field is an array of sprint objects. Extract the active sprint's name (first sprint where state == "active"), or the most recent if none are active. If the array is empty or null, show β€” (ticket not in a sprint β€” possibly backlog).

Sort the rows before rendering. JQL's cf[10020] sort is unreliable across sprint states, so re-sort client-side:

  1. Bucket by sprint state: active sprints first, then future sprints (by startDate ascending), then no-sprint / backlog last.
  2. Within each bucket, sort by priority P1 β†’ P2 β†’ P3 β†’ P4 β†’ P5 (treat missing/unknown priority as lowest).
  3. Within equal priority, preserve the JQL updated DESC order.

Keep it as a single table β€” the Sprint column makes the group boundary visible without subheadings.

Render:

### πŸ“‹ Jira β€” assigned to you

| Key | Sprint | Type | Pri | Status | Updated | Discussion | Summary |
|-----|--------|------|-----|--------|---------|------------|---------|
| [AB-649](https://.../browse/AB-649) | Sprint 42 | Task | P1 | In Progress | 2h | πŸ’¬ 3 Β· Jane Β· 40m | Stabilise identity cookies |
  • Key: markdown link to the Jira issue. Use the Jira base URL from the issue's self field, or a site-configured base (e.g. https://yourorg.atlassian.net/browse/{key}).
  • Sprint: active sprint name. Truncate numeric-only names to S{N} if the column gets wide. β€” if none.
  • Type: issuetype name (Task / Story / Bug / Sub-task).
  • Pri: shorten long names β€” P1 Critical β†’ P1, P2 High β†’ P2, etc.
  • Status: status name (In Progress / Code Review / Ready for QA / …).
  • Updated: relative time since updated (e.g. 2h, 4d).
  • Discussion: filled by the latest-discussion lookup below.
  • Summary: truncate to ~50 chars.

If no tickets are assigned, show _No open Jira tickets assigned to you._

If the Jira API returns an error, show _Jira unavailable: {error}_ and move on β€” do not fail the whole skill.

After the table, note whether the tickets span one sprint or multiple. Example: _All 6 in Sprint 42._ or _Spans 2 sprints: Sprint 42 (4), Sprint 43 (2)._ This answers "am I focused or scattered?" at a glance.

Latest Jira discussion

After the assigned-ticket search succeeds, fetch the newest comment for every returned ticket. These calls may run in parallel, but do not skip tickets just because their updated value is old:

mcp__jira__jira_get
  path: /rest/api/3/issue/{key}/comment
  queryParams:
    orderBy: -created
    maxResults: 1
  jq: '{total: .total, latest: (.comments[0] // null | if . == null then null else {author: .author.displayName, accountId: .author.accountId, created: .created} end)}'

Add a Discussion column to the assigned-ticket table:

| Key | Sprint | Type | Pri | Status | Updated | Discussion | Summary |
|-----|--------|------|-----|--------|---------|------------|---------|
| [AB-649](https://.../browse/AB-649) | Sprint 42 | Task | P1 | In Progress | 2h | πŸ’¬ 3 Β· Jane Β· 40m | Stabilise identity cookies |
  • Discussion: β€” when total is zero. Otherwise show πŸ’¬ {total} Β· {latest author first name or @accountId} Β· {relative age}. Do not render comment bodies in this compact table.
  • If a per-ticket comment request fails, show ? for that row and append _Some Jira discussion could not be fetched._ after the sprint note. A failed comment lookup must not hide the assigned-ticket table.
  • Keep the existing row sort; comments are awareness signals, not a reprioritisation rule.

2. πŸ”€ PRs β€” delegate to pr-status logic

If /landscape quick was invoked, skip this section entirely and add a one-line note: _PR section skipped (quick mode). Run /pr-status for full view._

Otherwise, follow the pr-status skill's instructions as-is (see ~/.agents/skills/pr-status/SKILL.md). Reuse its scripts directly β€” do NOT re-invoke the slash command:

  1. List open PRs org-wide via gh-pr-list-open.sh
  2. List recently closed via gh-pr-list-closed.sh
  3. Fetch details via gh-pr-details.sh (grouped by owner/repo)
  4. Render the same tables

Head this section ### πŸ”€ PRs instead of pr-status's own headings.

3. 🎯 Beads β€” in-progress + ready work

Run the beads.sh helper. It probes for bd, checks for .beads/ in the repo, and emits in-progress + ready listings as delimited sections. Do not call bd directly from this skill β€” always go through this script:

~/.agents/skills/landscape/scripts/beads.sh

Output sections (delimited by ---<NAME>---):

  • ---STATUS--- β€” OK, NO_BD (bd not installed), or NO_BEADS_IN_REPO (no .beads/ here)
  • ---IN-PROGRESS--- β€” output of bd list --status=in_progress (only if STATUS=OK)
  • ---READY--- β€” JSON array from next-bd --json (or plain text from bd list --ready fallback) (only if STATUS=OK)

If STATUS is NO_BD, render _Beads not installed β€” skipping._ and stop. If STATUS is NO_BEADS_IN_REPO, render _No beads in this repo._ and stop. Otherwise render the tables below.

In-progress beads

**In progress ({count})**
| ID | Pri | Type | Labels | Title |
|----|-----|------|--------|-------|
  • Include a Labels column. Show β€” if none.
  • If no in-progress beads: show _No in-progress beads._

Ready beads β€” sorted by sprint

The ---READY--- section is a JSON array (from next-bd --json). Each item has id, title, priority, issue_type, and rank.

Step 1 β€” Extract Jira keys. For each bead, scan title for the first match of [A-Z]+-\d+. If no match, the bead has no Jira link.

Step 2 β€” Batch Jira sprint lookup. If any keys were found, call:

mcp__jira__jira_get
  path: /rest/api/3/search/jql
  queryParams:
    jql: key in ({comma-separated keys})
    fields: summary,status,issuetype,priority,customfield_10020
    maxResults: 50
  jq: issues[*].{key: key, status: fields.status.name, sprint: fields.customfield_10020}

For each ticket's sprint array, pick the active sprint (first with state=="active"). If none active, pick the earliest future sprint (lowest startDate with state=="future"). If neither, treat as no-sprint.

Step 3 β€” Sort and cap. Bucket order: active sprint(s) β†’ future sprints (by startDate) β†’ no-sprint (has Jira key) β†’ no Jira link. Within each bucket preserve the rank order from next-bd. Cap the total at 5 beads. If more exist: _+{N} more β€” run /next sprint to see all._

Step 4 β€” Render. One table:

**Ready ({shown} of {total})**
| # | ID | Pri | Type | Jira | Sprint | Status | Title |
|---|----|-----|------|------|--------|--------|-------|
  • # is the picker index 1-N.
  • Jira column: markdown link [KEY](https://yourorg.atlassian.net/browse/KEY). Show β€” if no Jira key.
  • Sprint column: number + state suffix only (31 (active), 32 (future)) β€” strip the project prefix from sprint names like "PROJ Sprint 31". Show β€” if no sprint or no Jira.
  • Status column: Jira status. Show β€” if no Jira.
  • If no ready beads at all: _No ready beads. Run /triage to add work._
  • If the ---READY--- section is not valid JSON (fallback plain text): render it as-is, capped at 5 lines.
  • If the Jira call fails: render the table without Jira/Sprint/Status columns; add a footnote _Jira unavailable._

4. πŸ“ Working copy β€” current branch

Rendered LAST because it's the most immediate context β€” the branch you're sitting on right now, what needs committing/pushing, and whether it's in sync.

Run the working-copy.sh helper, which emits delimited sections for branch, dirty status, ahead/behind, last commit, and on-branch stash count:

~/.agents/skills/landscape/scripts/working-copy.sh

Output is grouped by ---SECTION--- markers. Parse and render from that.

Render:

### πŸ“ Working copy

| Field | Value |
|-------|-------|
| Branch | fix/AB-649-device-cookie-combined |
| Dirty | clean _(or: 3 modified, 1 untracked)_ |
| vs upstream | βœ… in sync _(or: ⬆ 2 ahead, ⬇ 1 behind)_ |
| Last commit | `abc1234` commit subject (2h ago) |

Notes:

  • If @{u} fails (no upstream), show no upstream tracking.

  • If output is empty for dirty, show clean.

  • Stashes: do NOT include a stash row in the table. Only surface stashes if there are stashes on the current branch. If non-empty, add a one-line footnote below the table:

    ⚠️ {N} stash(es) on this branch β€” run `git stash list` to review.
    

    Global stash count is not interesting β€” omit it.

  • Other worktrees: the OTHER-WORKTREES-UNSAFE section lists only worktrees (excluding the current one) that have uncommitted changes or unpushed commits. If empty, render nothing β€” worktrees that are clean and pushed are not interesting. If non-empty, add a footnote below the table:

    ⚠️ Other worktrees with unsaved work:
    - `/path/to/other` on `fix/X` β€” 3 modified, 2 unpushed
    

    Omit the dirty/unpushed parts that are zero (e.g. 3 modified alone, or 2 unpushed alone).

  • Recent handoffs for this repo: probe ~/.claude/handoffs/ via:

    ~/.agents/skills/handoffs/scripts/list.sh --summary-only
    

    Parse from the output:

    • ---SUMMARY--- β†’ current_repo_recent_live β€” recent handoffs for this repo that are still live work: not superseded and not finished (uses the same Monβ†’3 / Tueβ†’4 / elseβ†’3 weekend buffer as the closed-PR list). "Finished" here means all referenced beads are closed β€” a local bd check that runs even on this offline (--summary-only, no --check-branches) call, so a handoff whose task shipped no longer counts as a live thread to resume. Re-wraps of the same branch still collapse to one. (Merged-PR / Jira-Done detection needs the network and only applies under /handoffs's --check-branches; landscape's offline count catches the bead-closed case.)
    • ---CURRENT-REPO-LATEST--- β†’ a single {slug}|{branch}|{date} line for the newest current-repo handoff (the "last session"), or empty if none.
    • ---CURRENT-REPO-LIVE--- β†’ one {slug}|{branch}|{date}|{time} line per recent live (non-superseded, non-finished) current-repo handoff, newest first (these are the threads behind the current_repo_recent_live count). The first line equals ---CURRENT-REPO-LATEST--- when the newest handoff is itself still live; if the newest one is finished it's absent here, so the first line is the most recent resumable thread instead.

    If current_repo_recent_live > 0, render its own table (N = current_repo_recent_live) β€” a footnote got lost among the other tables, so give it the same ### {emoji} {Name} + table shape as the sections above:

    ### πŸ“₯ Recent handoffs ({N} live, last {RECENT-WINDOW-DAYS}d)
    
    | Handoff | Branch | When |
    |---------|--------|------|
    | `{slug}` πŸ“ | `{branch}` | {age} |
    | `{slug}` | `{branch}` | {age} |
    
    _`/handoffs` to browse and resume._
    
    • One row per ---CURRENT-REPO-LIVE--- line, newest first.
    • Handoff: the {slug}. Append πŸ“ to the row whose {slug} matches the ---CURRENT-REPO-LATEST--- line β€” that's the last session, the most likely resume target. When the newest handoff is already finished it won't appear here; the first row is then simply the most recent resumable thread, left unmarked.
    • Branch: the {branch}; render β€” when it is ? or empty.
    • When: relative age of {date} (e.g. today, 2d).
    • Cap at 5 rows (newest first). When N > 5, render the first 5 and replace the caption with _+{N βˆ’ 5} more β€” /handoffs to browse._

    Suppress the section entirely when current_repo_recent_live == 0 β€” silence is shorter. Older, superseded, or finished handoffs are still browsable via /handoffs; this table is just a fresh-work hint, deliberately offline (no --check-branches, so no branch-staleness here). This call can run in parallel with working-copy.sh.

4b. πŸ—‚οΈ Other repos in this workspace

working-copy.sh (Β§4) inspects only the cwd repo (plus its own worktrees). In a multi-repo workspace β€” mgit services (.mgit.conf) or git submodules (.gitmodules) β€” that silently misses uncommitted/unpushed state in sibling service repos. This is the single biggest blind spot at session start: you orient on the root repo and never notice that, say, dispatch was left with unpushed commits last night. Roll them up:

~/.agents/skills/wrap-up/scripts/multirepo.sh

It emits ---MARKER--- (mgit | submodules | none), ---ROOT---, and ---REPOS--- lines: {name}|{branch}|{ahead}|{behind}|{upstream}|{modified}|{untracked} (ahead/behind are - with no upstream; the root repo appears as its own row). This call can run in parallel with working-copy.sh β€” it's the same roll-up /wrap-up Β§3b uses.

  • ---MARKER--- is none β†’ single repo; skip this whole section silently (Β§4 already covered it).
  • Otherwise render only the members with something to report (ahead>0, behind>0, or modified+untracked>0); a clean+pushed member is noise. Skip the table entirely if every member is clean β€” in a healthy workspace this section shows nothing, which is the point.
### πŸ—‚οΈ Other repos in this workspace

| Repo | Branch | Unpushed | Behind | Uncommitted |
|------|--------|----------|--------|-------------|
  • Unpushed: {ahead}, or no upstream when upstream=no (local-only, never pushed).
  • Behind: show only when >0. A member that's diverged (ahead>0 AND behind>0) needs a rebase/pull before it can push β€” flag it explicitly: ⚠️ diverged β€” N ahead / M behind.
  • Uncommitted: {modified} modified / {untracked} untracked (omit zero parts).

Carry the most urgent member (diverged, then unpushed, then uncommitted) into the Β§5 Next suggestion β€” a sibling repo left in that state is exactly what a fresh session forgets.

5. Next step suggestion

After all blocks render, add a short footer with a concrete next step, picked from what's visible. Prefer the most load-bearing single action:

  • If the current branch's PR is approved, CI green, 0 threads, clean merge state β†’ suggest merging it (this unblocks stacked PRs).
  • If the current branch's PR has unresolved review threads β†’ suggest /review-comments.
  • If the current branch's PR is behind main β†’ suggest /rebase-main.
  • If there is uncommitted work β†’ suggest committing or stashing.
  • If a sibling service repo (Β§4b) is diverged β†’ suggest rebasing/pulling it before it can block a push (name the repo).
  • If a sibling service repo has unpushed commits or uncommitted work β†’ suggest pushing/committing it (name the repo).

Once those "finish / unblock" actions are clear, the suggestion becomes a pick-what-to-work-on decision. This is the morning "resume a handoff or start fresh?" question β€” arbitrate it here rather than leaving the user to choose between /handoffs and /next. Use the handoff signals from Β§4 (current_repo_recent_live and the ---CURRENT-REPO-LATEST--- {slug}|{branch}|{date} line):

  • If a recent live handoff is on the current branch (its {branch} equals the Β§4 working-copy branch) β†’ strongest resume signal: you're already sitting on its branch and it carries the open threads + suggested next step the bare branch doesn't. Suggest Resume {slug} β€” /handoffs.
  • If exactly one in-progress bead and no current-branch handoff β†’ suggest resuming the bead (show the ID).
  • If nothing decisive above but a recent live handoff exists (current_repo_recent_live > 0) β†’ lead with the handoff and name the fallback in one sentence, e.g. Resume {slug} (last session's thread) via /handoffs β€” or /next safe for fresh work. A warm thread beats a cold start, but the user keeps the choice.
  • If no live handoff and nothing in progress but ready beads exist β†’ suggest /next.
  • Otherwise β†’ suggest /triage or pulling a Jira ticket.

Format as one line:

---
**Next:** _{suggestion}_

Single sentence. Pick one action β€” don't list a menu. The one exception is the handoff-fallback branch above, which deliberately names a single fallback (Resume {slug} … β€” or /next safe …) so the morning "resume or start fresh?" choice stays visible in one sentence.

Failure modes

Each block is independent β€” a failure in one must not prevent the others from rendering.

  • Not in a git repo: skip the Working-copy block, print _Not in a git repository._ in its place.
  • No Jira MCP configured: skip the Jira block, print _Jira MCP not configured._.
  • gh not authenticated: skip the PR block, print _GitHub CLI not authenticated (run \gh auth login`)._`.
  • No beads in repo: skip the Beads block, print _No beads in this repo._.
  • Single repo (no .mgit.conf/.gitmodules): the Β§4b roll-up emits MARKER=none β€” skip that block silently; Β§4 already covers the one repo.

Performance notes

  • Run the git commands in parallel (single Bash call, or parallel tool calls).
  • The PR section dominates runtime β€” that's why /landscape quick skips it.
  • Don't re-render pr-status's "deltas since last check" β€” landscape is a snapshot, not a diff.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.