plugins/lisa-agy/skills/repair-intake/SKILL.md
Vendor-agnostic repair scanner — the recovery counterpart to lisa:intake. Where intake claims `ready` work, repair-intake finds work that got stuck or was left half-closed: items left in `blocked`, stalled in an in-progress role (build `claimed`, PRD `in_review`), terminal-labeled items that are still natively open, and rollup/container items whose children are all terminal but whose parent is not closed out. Scans the same queues lisa:intake serves (Notion / Confluence / Linear / GitHub PRD databases; JIRA / GitHub / Linear build queues), enumerates candidates up to `max_candidates`, and repairs every materially actionable one in that bounded set: resumes stalled in-progress work IN PLACE (build → the vendor agent + the scanner's post-agent transition; PRD → the source `*-to-tracker` dry-run validate→route pipeline) — but for a stalled build it first diagnoses the PR/deploy state: a PR that already merged is recovered by applying the env transition build-intake never got to (no re-dispatch); a PR that is merely behind its base is re-synced in place via `gh pr update-branch` so the already-enabled auto-merge can land (a clean rebase needs no human); and only a PR that cannot merge for a non-mechanical reason (true conflict, failing checks, unaddressed CodeRabbit/changes-requested) or a failed deploy gets a build-ready leaf fix ticket with the item moved to `blocked` (blocked by that ticket) rather than re-dispatching, re-validates blocked PRDs when new clarifying answers exist, re-dispatches blocked build items whose `is blocked by` dependencies have since closed OR whose validation/quality-gate self-block now re-validates PASS (re-running `lisa:tracker-validate` against current content — the build mirror of PRD re-validation), performs terminal native closure for terminal-labeled items, reconciles parent rollups to their derived state per leaf-only-lifecycle — including the intermediate-env case (e.g. all children at `On Stg` → parent `On Stg`) and a container wrongly stuck in `ready` — and closes out rollups whose associated child work is fully terminal. Idempotent, loop-protected via a [lisa-repair-intake] marker + state fingerprint + backoff. Never mutates product-owned states (`draft`, `verified`) and never touches `ready` leaves (a container wrongly carrying `ready` is the one exception — it is rolled up from its children, since `ready` on a parent is an invariant violation, not intake's claim signal). Designed as a /schedule cron target running alongside lisa:intake.
npx skillsauth add codyswanngt/lisa repair-intakeInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Run one batch-repair cycle against the queue identified by $ARGUMENTS. Where lisa:intake
scans the ready role and moves work forward, repair-intake scans the stuck and
close-out roles and moves work unstuck or fully closed:
claimed, PRD
in_review) whose processing cycle died. It is technically "being worked" but nothing is
happening, so it sits ignored forever. (The vendor PRD intakes explicitly leave an errored PRD
in in_review "for the human to investigate from there" — that orphan is exactly what this
skill recovers.) For a stalled build, repair-intake first diagnoses why it stalled by
inspecting its PRs and deploys. A PR that already merged is recovered by applying the env
transition build-intake never got to (its merge gate left the item claimed when the merge landed
after its agent returned) — no re-dispatch. A PR that is merely behind its base (BEHIND, no
conflict) is re-synced in place with gh pr update-branch so the already-enabled auto-merge can
finally land — a clean rebase needs no human, and leaving it stranded is the exact gap that lets an
auto-merge PR sit unmerged forever. Only a PR that cannot merge for a non-mechanical reason (true
conflict / failing checks / unaddressed CodeRabbit or CHANGES_REQUESTED review) or a failed deploy
gets a build-ready leaf fix ticket with the item moved to blocked (blocked by that ticket) instead
of blindly re-dispatching the agent — which would just churn against an unmergeable PR.blocked whose blocker may now be gone. The blocker is
one of three classes, and repair re-checks all of them, not just dependencies: (a) an
is blocked by dependency has since closed; (b) a validation / quality-gate self-block —
the item was bounced to blocked by its own pre-flight verify/validate gate (missing
Validation Journey, Sign-in Required, Acceptance Criteria, etc.) with no dependency at all,
and a human has since edited the item to add what the gate demanded; or (c) clarifying
questions answered / an ambiguity research can now settle. A self-block (b) is the common
one missed by dependency-only re-checks: nothing else is blocking it, so re-running the same gate
against its current content is the only way to know it is now passable.status:done) but still open/active in the provider's native state.leaf-only-lifecycle. This covers the completed case (all children terminal → close the parent
out) and the intermediate-env case (all children shipped to an env like On Stg, but the
parent never advanced — including a parent left stranded in a status it should never carry).ready container — a parent/container (open child work, or a childless
Epic) wrongly carrying the build-ready role. This is a leaf-only-invariant violation
the build-intake claim gate deliberately leaves for a human; repair-intake reconciles it by
rolling the parent up from its children (with an audit note), so a container never sits in ready
indefinitely.This skill is the symmetric counterpart to lisa:intake. It reuses the same queue-detection,
the same agent-team orchestration, the same "don't ask, just run" confirmation policy, and the
same per-item surfaces the vendor intakes use (lisa:<source>-to-tracker dry-run for PRDs;
lisa:<tracker>-agent + the scanner's lifecycle transitions for build) — it differs in which
roles it scans and, for stalled/blocked work, that it skips the claim step (the item is already
claimed/blocked). Close-out candidates do not dispatch agents; they only reconcile terminal
lifecycle state with provider-native closure and rollup state.
/lisa:repair-intake <queue> [intake_mode=prd|build|both] [stale_after=2h] [max_candidates=100] [force=true]
| Token | Meaning | Default |
|-------|---------|---------|
| <queue> | Same queue identifier lisa:intake accepts (see Source dispatch). Required. | — |
| intake_mode | prd | build | both. Only meaningful for a GitHub org/repo (or bare github) that hosts both PRD and build label namespaces. both is unique to repair — a repair sweep usefully covers both lifecycles in one schedule. Absent → both when both namespaces exist, else whichever lifecycle exists. | both for dual GitHub queues; otherwise infer |
| stale_after | How long with no observable activity before an in-progress item counts as stalled. Accepts 24h, 90m, 2d, or 0 (treat any in-progress item as stalled — manual recovery, also the only way to resume work on a provider that exposes no reliable timestamp). Overrides config. | 2h |
| max_candidates | Cap on how many stuck/close-out candidates to enumerate and evaluate. Repair every materially actionable candidate within this bounded set, then stop. Overrides config. | 100 |
| force | true bypasses the loop-prevention backoff window (so a manual re-run re-attempts items even if their fingerprint is unchanged). It does not change the staleness rule — use stale_after=0 for that. | false |
Do NOT ask the caller whether to proceed. Once invoked with a queue, run the cycle to completion. The caller (a human at the CLI or a scheduled cron) has already authorized the run by invoking the skill; re-prompting defeats the purpose of a background repair sweep.
Specifically forbidden:
blocked. Returning an item to blocked with a current, accurate note is a
valid outcome of the repair lifecycle, not a failure.max_candidates and the actionable subset inside that cap; the cost of stalling a scheduled
cron waiting on a human is unbounded.The only legitimate reasons to stop early:
If you are NOT already operating inside an agent team (no prior successful team-creation or subagent-delegation tool call in this session, not spawned into a team context), the very first thing you do is establish team orchestration.
Use the team tool for the current runtime:
TeamCreate. If TeamCreate has not been loaded yet, first use ToolSearch with
query: "select:TeamCreate" to load its schema.TeamCreate; Codex does not expose that Claude tool. Use tool_search
with a query like multi-agent tools to load multi_agent_v1, then use
multi_agent_v1.spawn_agent for teammate delegation. Treat the first successful spawn_agent
call as establishing team orchestration.If no team creation or subagent delegation tool is available, explicitly state that team orchestration is unavailable in this runtime, continue as the lead agent, and preserve the workflow's review, verification, and task-tracking obligations locally.
Until the team is established, the first Codex teammate has been spawned, or the no-team
fallback has been declared, do NOT call any of: Agent, TaskCreate, Skill, MCP tools
(Atlassian / Linear / GitHub / Notion), Read, Write, Edit, Bash, Grep, Glob.
Scanning the queue, evaluating staleness, and dispatching per-item repairs — all of those are
tasks for the team you are about to create, not for the lead session before orchestration
exists.
If you ARE already inside an agent team (e.g., a teammate invoked this skill via the Skill tool), do NOT create a second team — many harnesses reject double-creates — and do NOT collapse the nested flow into a single inline worker. A nested team-first flow must still bring in the specialists it requires by adding them to the existing team, not by doing the work itself:
Agent with a name from a teammate (the harness rejects it: "Teammates cannot spawn other teammates — the team roster is flat"). Send the team lead a message naming the specialist teammate(s) this flow needs, their task assignments, and completion criteria, then coordinate through the shared task list until they finish. An anonymous subagent (Agent with name omitted) is permitted only for bounded one-shot work whose result returns directly to you — it is not a substitute for the required lifecycle specialists.TeamCreate. If the lead/root agent is addressable (you were given its id/handle), send it a request to multi_agent_v1.spawn_agent the specialist agent(s), including each agent's prompt, ownership, and expected result. If no lead handle exists but spawn_agent is available to you, spawn only the bounded specialist agent(s) this flow needs, wait_agent for their results, and relay those results upward to the parent/lead.Treat the first successful lead-spawn request (or, on the Codex fallback, the first specialist spawn) as preserving team orchestration. Never satisfy a team-first lifecycle flow by doing all the work inline. The cycle's outer team is created by repair-intake. Each per-item repair it runs
(lisa:<source>-to-tracker for a PRD, lisa:<tracker>-agent for a build item) executes within
the same team — those skills' orchestration preambles detect the existing team and skip creating
a second one. One team per cron cycle.
Detect the queue type from $ARGUMENTS using the exact same detection and disambiguation
rules as lisa:intake — read that skill's "Source dispatch" section for the authoritative
table; the detection is identical and only the per-item action changes (repair instead of
claim-and-advance). The essentials, inlined here so this skill is self-complete:
| If $ARGUMENTS is... | Queue / lifecycle | Source/tracker key | Candidates repaired |
|------------------------|-------------------|--------------------|----------------------|
| Notion database URL/ID | PRD (Notion) | source=notion | in_review, blocked, terminal/open PRDs, all-terminal generated-work rollups |
| Confluence space URL/key | PRD (Confluence) | source=confluence | in_review, blocked, terminal/open PRDs, all-terminal generated-work rollups |
| Confluence parent page URL/ID | PRD (Confluence, narrowed) | source=confluence | in_review, blocked, terminal/open PRDs, all-terminal generated-work rollups |
| Linear workspace URL, team URL/key, or literal linear | PRD (Linear) | source=linear | in_review, blocked, terminal/open PRDs, all-terminal generated-work rollups |
| GitHub repo URL / org/repo (PRD namespace) | PRD (GitHub) | source=github | in_review, blocked, terminal/open PRDs, all-terminal generated-work rollups |
| GitHub repo URL / org/repo with tracker = github (build namespace) | Build (GitHub) | tracker=github | claimed, blocked, terminal/open issues, parent rollups (intermediate-env + all-terminal), stale-ready containers |
| Literal github | GitHub; route by intake_mode (prd / build / both) | per lifecycle | per lifecycle above |
| JIRA project key or full JQL | Build (JIRA) | tracker=jira | claimed, blocked, terminal/closure verification, parent rollups (intermediate-env + all-terminal), stale-ready containers |
Disambiguation (same as lisa:intake): a notion.so/notion.site URL → Notion; an Atlassian
/wiki/spaces/<KEY> URL → Confluence (with /pages/<id> → parent-page narrowing); a
linear.app workspace/team URL or literal linear → Linear; a github.com URL / <org>/<repo>
token / literal github → GitHub; a bare token matching the JIRA project-key regex → JIRA
(else try Confluence space, then Linear team); a string with JQL operators → JQL. A single-item
URL is out of scope — this skill is batch-only; repair one item by hand via lisa:implement
(build) or by re-running lisa:<source>-to-tracker (PRD).
Role names for every vendor are resolved from .lisa.config.json per the config-resolution
rule — never hardcode status/label strings. The relevant repair roles:
| Lifecycle | Vendor | In-progress role key | Blocked role key | Terminal / rollup role key |
|-----------|--------|----------------------|------------------|----------------------------|
| Build | JIRA | jira.workflow.claimed (In Progress) | jira.workflow.blocked (Blocked) | env-resolved jira.workflow.done |
| Build | GitHub | github.labels.build.claimed (status:in-progress) | github.labels.build.blocked (status:blocked) | env-resolved github.labels.build.done (status:done) |
| Build | Linear | linear.labels.build.claimed (status:in-progress) | linear.labels.build.blocked (status:blocked) | env-resolved linear.labels.build.done (status:done) |
| PRD | Notion | notion.values.in_review (In Review) | notion.values.blocked (Blocked) | notion.values.shipped (Shipped) |
| PRD | GitHub | github.labels.prd.in_review (prd-in-review) | github.labels.prd.blocked (prd-blocked) | github.labels.prd.shipped (prd-shipped) |
| PRD | Linear | linear.labels.prd.in_review (prd-in-review) | linear.labels.prd.blocked (prd-blocked) | linear.labels.prd.shipped (prd-shipped) |
| PRD | Confluence | confluence.parents.in_review (page id) | confluence.parents.blocked (page id) | confluence.parents.shipped (page id) |
In addition to the lifecycle roles above, the build lifecycle defines the human_needed marker — an additive label (jira.labels.human_needed / github.labels.build.human_needed / linear.labels.build.human_needed, default Human Needed / human-needed) that rides alongside blocked when the block needs human-only input no agent or retry can supply (see config-resolution "Build markers"). repair-intake's interaction with the marker is asymmetric and is the whole point of the distinction below:
blocked blocked by that ticket, expecting the next cycle to self-heal. Those are not human_needed; if such an item arrives already carrying a stale human_needed marker, repair-intake clears it (the block is no longer waiting on a human).human_needed already — the agent owns that marker. repair-intake leaves it in place.Resolve with the standard role-read pattern (local overrides global, default fallback):
read_role() {
local path="$1" default="$2"
local local_v global_v
local_v=$(jq -r "${path} // empty" .lisa.config.local.json 2>/dev/null)
global_v=$(jq -r "${path} // empty" .lisa.config.json 2>/dev/null)
echo "${local_v:-${global_v:-$default}}"
}
# e.g. build/github:
CLAIMED=$(read_role '.github.labels.build.claimed' 'status:in-progress')
BLOCKED=$(read_role '.github.labels.build.blocked' 'status:blocked')
repair-intake stays vendor-neutral; concrete reads/writes go through the same layers the vendor
intakes use. Never call Atlassian MCP or acli directly — go through lisa:atlassian-access.
| Vendor | Reads (scan / comments / links) | Writes (transition / comment / close-out) | Re-dispatch / re-validate |
|--------|---------------------------------|-------------------------------|---------------------------|
| JIRA (build) | lisa:atlassian-access search-issues / lisa:jira-read-ticket | lisa:atlassian-access transition / comment | lisa:jira-agent |
| GitHub (build) | gh issue list / gh issue view --json / gh pr list / GraphQL sub-issues | gh issue edit (labels) / gh issue comment / gh issue close --reason completed | lisa:github-agent |
| Linear (build) | Linear MCP list_issues / get_issue / list_comments | Linear MCP save_issue (labels) / save_comment | lisa:linear-agent |
| Notion (PRD) | lisa:notion-access (query, page comments) | lisa:notion-access write-page (status) / page comment | lisa:notion-to-tracker (dry-run) |
| GitHub (PRD) | gh issue list/view (PRD labels) / GraphQL sub-issues / generated-work section | gh issue edit / gh issue comment / gh issue close --reason completed | lisa:github-to-tracker (dry-run) |
| Linear (PRD) | Linear MCP list_projects / get_project (+ sentinel feedback issue) | Linear MCP save_project (labels) / save_comment | lisa:linear-to-tracker (dry-run) |
| Confluence (PRD) | lisa:atlassian-access CQL | lisa:atlassian-access page parentId update / comment | lisa:confluence-to-tracker (dry-run) |
An in-progress item (build claimed, PRD in_review) is stalled only if it shows no
observable activity newer than the stale_after threshold. blocked items are NOT gated on
staleness — their repairability is judged on current blocker/answer state, not elapsed time.
$ARGUMENTS stale_after=<dur> (one-off override) — always wins. Parse Nh / Nm / Nd /
0 into hours..lisa.config.json intake.repair.staleAfterHours (durable project default).stale_after=0 means "treat any in-progress item as stalled" — a manual full-recovery lever,
and the only way to resume work on a provider that exposes no reliable activity timestamp.
Compute the item's newest activity timestamp from the highest-priority signal the vendor
exposes, and compare it to now - stale_after:
updatedAt / last_edited_time / updated.If ANY of these is newer than the threshold, the item is active → record it as active and
skip it (read-only). For build claimed, an open PR with recent commits/checks is active. For
PRD in_review, a recent comment or page edit is active.
Count only forward-progress signals as keep-alive: new commits, a review that was just
requested or posted, an in-progress/queued check run, a fresh progress comment. A settled
blocker state — a failing/errored check run, CONFLICTING mergeability, a CHANGES_REQUESTED
review, an unaddressed CodeRabbit/reviewer change request, or a failed deployment — is NOT
keep-alive activity: it does not reset the staleness clock. The clock runs from the last genuine
progress event, so a PR that has been sitting failed/conflicted/awaiting-changes for longer than
stale_after counts as stalled and is diagnosed below.
If a provider cannot expose any reliable timestamp, do not auto-resume its in-progress
items unless the caller passed stale_after=0. (Dependency-cleared blocked repair still
proceeds — it is judged on blocker state, not time.)
Apply per candidate. Continue through the ordered list until every candidate inside the
max_candidates cap has been evaluated. Each candidate may trigger a write (lifecycle transition,
native close/archive/complete, re-dispatch, or refreshed note), be recorded read-only, or be
recorded under Errors. Do not stop after the first write; the cap is the batch boundary.
claimed (stalled in-progress) → diagnose blocker, else resume in placeAfter the staleness gate passes, first diagnose why it stalled by inspecting the item's PRs and deploys (see "Stuck-cause diagnosis" below). A stalled build usually stalled for a concrete external reason, and re-dispatching the agent at it will not fix a PR that cannot merge or a deploy that failed — it just churns.
claimed because the merge landed after its agent returned. Do not re-dispatch
or file anything — apply the scanner's post-agent env-resolved claimed → done transition
directly (step 2 below, env-resolved), and record it. This is the recovery arm for build-intake
leaving merged-but-unadvanced items in claimed.claimed; a later cycle confirms the merge and transitions. Do not file a fix
ticket for a clean rebase.CHANGES_REQUESTED / unaddressed CodeRabbit; or a failed deploy) → do not
dispatch the agent. File a build-ready leaf fix ticket for the blocker, move this item
claimed → blocked with an is blocked by link to that ticket, and record it. The existing
"Build blocked → unblock if cleared" path resumes this item on a later cycle once the fix
ticket is terminal — a self-healing loop. Skip the resume steps below.If the PR is healthy in-flight and no blocker is found, the work simply died mid-flight — run the same per-item sequence
the vendor build-intake runs, skipping the claim transition (the item is already claimed):
lisa:jira-agent / lisa:github-agent /
lisa:linear-agent (matching the queue's tracker) — with the item ref. This resumes the work
in place, preserving its existing branch/PR and prior comments.claimed → done,
where done is env-resolved exactly as lisa:<tracker>-build-intake resolves it (per
config-resolution env-keyed done: explicit target_env arg wins; else reverse-lookup the
env from the resulting PR's base branch via deploy.branches; if done is a map and env is
unresolvable, fail loudly — never guess). repair-intake owns this transition because it is
standing in for the scanner that never got to finish it.blocked
with a [lisa-repair-intake] note (see Loop prevention). When the surfaced blocker is something
only a human can supply (credentials, access/permissions, a product or scoping decision), the
item also carries the human_needed marker — the vendor agent's pre-flight gate applies it; if
repair-intake makes the block transition itself for such a reason, it adds the marker too. (A
block that another tracked ticket or retry will clear is not human-needed — that is the
auto-recoverable fix-ticket path above.)Do not reset stalled in-progress items to
ready. Reset throws away state, makes a partially-built item look freshly human-approved to the nextlisa:intakeclaim, and forces a two-cycle recovery. Resume in place.
Run this for every stalled claimed build item before considering an agent re-dispatch. The
goal is to distinguish "work died mid-flight, just resume it" from "work is blocked on a concrete
external state that resuming the agent cannot fix."
1. Find the associated PR(s) and deploy(s). From the item's linked PRs (GitHub: remote/dev
links and gh pr list --search <issue-ref>; JIRA: dev-status / remote links; Linear: attachments
and git-branch links) and the deploy(s) for the resulting merge (the env-keyed deploy.branches
mapping from config-resolution). Read each PR with the vendor's native state, e.g. GitHub
gh pr view <n> --json state,mergedAt,mergeable,mergeStateStatus,reviewDecision,statusCheckRollup,comments,reviews.
2. PR already merged → recover, don't re-dispatch. If state == MERGED, the build is effectively
complete and the only thing missing is the env transition the build-intake never applied (its merge
gate left the item claimed because the merge landed after its agent returned). Do not re-dispatch
or file anything: apply the scanner's post-agent env-resolved claimed → done transition (the
resume-sequence step 2, env-resolved from the merged PR's base branch) and record it as a repair
write. Where the env deploy is observable, confirm it did not fail first; a failed post-merge deploy
falls through to the blocker path (step 4).
3. PR only behind its base → re-sync in place (mechanical, not a blocker). If the PR is clean but
behind its base — mergeStateStatus == BEHIND while mergeable != CONFLICTING and no required check
is failing — it does not need a human. This is exactly the case that strands a PR forever: GitHub
auto-merge will not advance a BEHIND branch on its own, so a PR opened with --auto sits unmerged
until something rebases it. Re-sync it in place and let the existing auto-merge land it:
gh pr update-branch <n> # rebase/merge the base into the PR head; reruns required checks
Record this as a repair write (resynced), keep the item claimed, and move on — a later cycle sees
the now-CLEAN (or merged) PR and either lets auto-merge finish or applies the merged-PR recovery in
step 2. Only if gh pr update-branch itself reports a conflict it cannot apply does the PR become a
true conflict (step 4). Honor the backoff window so repeated cycles don't re-issue update-branch on
an unchanged head (Loop prevention). For JIRA/Linear items the PR is still the GitHub PR backing the
branch — operate on it the same way.
4. Classify as a blocker. Treat any of these as a real external blocker:
mergeable = CONFLICTING or mergeStateStatus = DIRTY (overlapping
changes a plain rebase cannot resolve), or gh pr update-branch (step 3) reported a conflict. A
merely BEHIND branch is not here — it was re-synced in step 3.statusCheckRollup has a FAILURE/ERROR/TIMED_OUT conclusion,
or mergeStateStatus = UNSTABLE/BLOCKED due to checks.reviewDecision = CHANGES_REQUESTED, or unresolved CodeRabbit
(or other reviewer) comments that request changes and have not been addressed by a newer commit.mergeStateStatus = BLOCKED for a reason other than
a transient check still running.A check that is still queued/in progress, or a CLEAN/HAS_HOOKS mergeable PR with no
outstanding change request, is not a blocker — that is normal in-flight state. (Such a PR with
recent check/commit activity would already have been caught as active by the staleness gate.)
5. On a blocker found → file a leaf fix ticket + block the item.
lisa:tracker-write (the
vendor-neutral leaf writer + validation gate; never a vendor *-write-* skill directly),
issue_type: Bug for a failing-check/conflict/failed-deploy, Task for review-feedback
follow-up, build_ready: true so it auto-builds. The ticket MUST name: the blocked item + its
PR/deploy URL, the exact blocker (conflict / which checks failed with their logs link / which
change requests / which deploy run), three-audience description, and Gherkin acceptance criteria
for "PR is mergeable / deploy is green."claimed → blocked and add an is blocked by link to the
new fix ticket (vendor-native: JIRA issue link is blocked by; GitHub/Linear Blocked by: line
[lisa-repair-intake] note naming what it is blocked by and why. This block is
auto-recoverable — the fix ticket will build and close on its own — so do not add the
human_needed marker, and if the item already carries a stale human_needed label, remove it
here (it is no longer waiting on a human). The human_needed marker is reserved for blocks a
human must clear; this one a later cycle clears automatically.The item now sits in blocked; once the fix ticket reaches a terminal state, the Build
blocked → unblock if cleared path (next section) detects the cleared is blocked by
dependency and resumes the original in place — a self-healing loop.
Idempotency. Before filing, check for an open fix ticket already carrying the marker
[lisa-repair-intake] blocker:<item-ref>/<blocker-key> (blocker-key is a stable slug of the
blocker, e.g. pr-1234/merge-conflict or pr-1234/checks-failing). If one exists, reference it
and ensure the is blocked by link is present rather than creating a duplicate. Honor the backoff
window and state fingerprint (Loop prevention) so re-runs over the same unchanged blocker are no-ops.
blocked → re-evaluate, unblock if clearedis blocked by links, therefore nothing to do." A self-block has zero dependencies by
definition, yet is fully re-checkable.is blocked by dependency is cleared → move
blocked → claimed, then run the same agent-dispatch + post-agent claimed → done sequence as
the stalled-claimed path above (one-cycle recovery). If the agent re-blocks, move back to
blocked — a valid outcome.verify/validate gate failure (its [lisa-*] block note carries a gate marker + a "Missing
requirements" list and there is no open is blocked by dependency), re-run the same gate
against the item's current content via lisa:tracker-validate (read-only; the vendor-neutral
gate lisa:<tracker>-build-intake and lisa:<tracker>-write-* already use). This is the build
mirror of the PRD blocked → re-validate path below.
blocked → claimed and resume exactly
as in (2): agent-dispatch + post-agent claimed → done.blocked, but refresh the note with the current (usually smaller)
missing-requirement set so the human sees what remains. Because the fingerprint includes the
gate verdict + missing-requirement set (Loop prevention), a partial human fix changes the
fingerprint and re-checks next cycle, while a truly-unchanged gate result stays in backoff.lisa:codebase-research / lisa:product-walkthrough); if resolved, proceed
as in (2).blocked.For each build item that already carries the env-resolved true terminal done role but is still
native-open / active / unresolved:
[lisa-repair-intake]
note naming the incomplete child set.done role is the true final value per leaf-only-lifecycle and
config-resolution env-keyed done. Intermediate env labels (for example status:on-dev or
status:on-stg) are not terminal and must stay open.gh issue close <number> --repo <org>/<repo> --reason completed.statusCategory = Done, resolution set if required);
if not, transition through the configured terminal workflow path or report the missing setup.[lisa-repair-intake] note only when the native close-out changed state or when
an actionable setup error must be surfaced. Do not spam already-closed terminal items.For each parent/container item (an Epic, a Linear Project, or any item — of any type — with open child work),
reconcile its lifecycle state with the roll-up of its children — including the intermediate-env
case, not only fully-terminal close-out. This is the recovery-side complement to the forward
rollup the *-sync --rollup skills perform; it catches a parent that was never rolled up (or was
left in a status it should not carry, including a stale build-ready ready).
leaf-only-lifecycle Parent status
rollup state machine, evaluated over the env ladder in-progress < dev < staging < production (the ordered keys of the env-keyed done map): any required child blocked →
blocked; else every required child shipped to some env → the least-advanced env among
them (e.g. all On Stg → On Stg); else any child started → claimed; else unchanged.
Optional / won't-do / not-planned children are terminal-but-dropped and do not hold the parent
open.status:*),
removing any conflicting stale build lifecycle role — including a stale ready the parent
should never carry. Post an idempotent [lisa-repair-intake] rollup note naming the derived
state and the child tally (honor the backoff window + fingerprint).done. When — and only when — the derived
env is the production/terminal value, finalize through the provider-native mechanism (GitHub
gh issue close --reason completed, Linear move to Done state, JIRA resolved/closed verified at
statusCategory = Done). An intermediate-env rollup (On Dev/On Stg) advances the parent's
status but must not close it — it is still open per leaf-only-lifecycle.unchanged (children exist but none started) or the required set is
ambiguous / inaccessible, leave the parent as-is and record it as active or still_blocked
with the current child tally; never guess a transition.in_review (stalled in-progress) → re-run validate→routeAfter the staleness gate passes, run the same dry-run validate→route pipeline the vendor PRD
intake runs per item, targeted at this single PRD and skipping the claim (it is already
in_review):
lisa:<source>-to-tracker with dry_run: true and the PRD's URL (source = the queue's
PRD vendor: notion-to-tracker / confluence-to-tracker / linear-to-tracker /
github-to-tracker). This indirectly runs lisa:tracker-source-artifacts,
lisa:product-walkthrough, and the lisa:tracker-validate gate, returning a structured
PASS/FAIL report with prd_anchor snippets — the same report the PRD intake consumes.lisa:<source>-to-tracker with dry_run: false to write the tickets
(its full run already writes the PRD back-link via lisa:prd-backlink), run the
lisa:prd-ticket-coverage audit as the PRD intake does, then transition the PRD to its
ticketed role via the access layer.prd_anchor (page-level for
prd_anchor: null), tagged [lisa-repair-intake] (Loop prevention), and transition to
blocked.blocked → re-validate if new answers exist[lisa-repair-intake] note or the original blocked note. For Linear include the
sentinel feedback issue and anchored sub-issue comments; for Confluence include inline/footer
comments where the access layer exposes them; for Notion include page comments and
last_edited_time.lisa:<source>-to-tracker dry-run validate→route pipeline as
in PRD in_review above (skipping claim). PASS → ticketed; FAIL → refresh note, stay
blocked.blocked untouched (subject to the
backoff window — do not re-post an identical note).For each PRD source artifact that already carries the configured terminal source role (shipped
for generated-work completion, or a source-specific terminal role that the configured PRD source
declares closed-out) but is still native-open / active:
prd-lifecycle-rollup, unless the
source artifact is already in a stronger product-owned terminal role that explicitly permits
closure. Do not move a PRD out of draft or verified.--reason completed.verified; /lisa:verify-prd remains the only automated writer of the verified
role. This path only reconciles an already-terminal PRD with native closure.For each PRD in ticketed or another non-product-owned open PRD role whose generated top-level
work is fully terminal:
prd-ticket-coverage / the vendor PRD intake
does: native PRD children where supported, plus the durable generated-work section fallback.prd-lifecycle-rollup's vendor predicate. A generated Epic or
Story is terminal only when it has itself rolled up and closed out; do not re-derive its leaf
descendants directly when its own state is still open.shipped role.verified and does not run /lisa:verify-prd.A blocked build item is held by one or more of three blocker classes. Identify which are present
from the item's block note(s) and links, then clear-check each present class — an item with no
dependency is not automatically un-actionable; it may be a self-block that now passes.
lisa:tracker-read is a thin dispatcher that returns each vendor's bundle verbatim — there
is no normalized is blocked by field. Read the bundle, then extract blockers per vendor:
lisa:github-build-intake documents — Blocked by: #123,
qualified cross-repo refs (owner/repo#123), issue URLs in the body/comments — plus timeline
cross-reference events.lisa:jira-read-ticket returns and select the
is blocked by link type.get_issue and select
blocker relations.Then classify each blocker:
done role — not only the production terminal. The done role is configured
per-env as a {dev, staging, production} map (config-resolution), so On Dev, On Stg,
and production Done all mean the blocker's code is merged and deployed to ≥1 environment.
A post-build review role (e.g. Code Review) is likewise cleared — the change exists and is
in flight. An is blocked by link is a development dependency: it is satisfied once the
blocker's code is in trunk; it must NOT wait for the blocker to reach production. (This matches
the intake-path dependency-hold gate in lisa:intake-explain, which already treats
code-review / on-dev / on-stg / done as cleared — repair-intake must not be stricter.
In an env-staged workflow where Done means "in production", a strict production-terminal
check strands every dependent forever behind a blocker that is already merged and sitting at
On Stg / On Dev.)ready / claimed / unknown — code not yet in trunk) → still
blocking.Only re-dispatch when every parsed blocker is cleared. When in doubt, stay blocked — a false-negative (left blocked) is cheap; a false-positive (re-dispatched into a real blocker) wastes a build cycle.
A self-block has no is blocked by dependency: the build-intake/agent flow claimed the item,
its pre-flight verify/validate gate failed (missing Validation Journey, Sign-in Required,
Target Backend Environment, Repository, Out of Scope, Evidence manifest, weak Acceptance Criteria,
etc.), and the item was bounced to blocked carrying that gate's [lisa-*] note + "Missing
requirements" list. Detect it by: (1) the block note bears a known gate marker (e.g.
Pre-flight verify gate: BLOCKED, jira-verify / *-validate-*), and (2) there is no open
is blocked by dependency. (If both a dependency and a self-block are present, clear the
dependency via Class A first; the self-block re-check still gates the eventual re-dispatch.)
Clear-check by re-running the same gate against current content — lisa:tracker-validate
(read-only; never writes), which dispatches to lisa:<tracker>-validate-* exactly as the write
path and build-intake do, so the bar cannot drift:
Conservative, same as Class A: a still-failing gate is a real blocker — never re-dispatch a build
whose own gate has not yet passed. This is intentionally symmetric with the PRD blocked → re-validate path: PRDs re-run their dry-run validate→route when source content changes; builds
re-run tracker-validate when item content changes. The asymmetry where build blocked checked
only dependencies — leaving verify-gate self-blocks stranded forever after a human filled in the
missing sections — is the gap this class closes.
A block that research or a human answer can settle (no dependency, no failing gate). Re-check by
running the needed research (lisa:codebase-research / lisa:product-walkthrough) or detecting a
human comment/edit newer than the last [lisa-repair-intake] note. Resolved → proceed to
re-dispatch; else stay blocked.
A blocked item with a permanently unresolved problem must not be "repaired" and re-noted every
cron tick.
[lisa-repair-intake] and carries a compact state
fingerprint: the lifecycle role, the set of blocker refs + their observed states, the
validation verdict (PASS/FAIL) plus the current missing-requirement set for a Class-B
self-block (so a human filling in one of several missing sections changes the fingerprint and
triggers a re-check next cycle, rather than being suppressed as a no-op), terminal/open state,
rollup child tally, and a timestamp.blocked item, compute the current fingerprint. If
an identical fingerprint was already posted within the backoff window, skip the item
silently (record as still_blocked / active, no write).stale_after (2h). force=true bypasses backoff for a manual run.repair-intake owns the repair surfaces needed to recover stuck work and close-out drift:
build claimed / blocked, PRD in_review / blocked, terminal-labeled native-open items,
parent/container rollups (intermediate-env and fully-terminal), and stale-ready containers.
It MAY:
claimed → done on a successful resume (it is finishing
the scanner's interrupted job), and move a dependency-cleared build item blocked → claimed.human_needed marker on build blocks: leave it where the vendor agent set it (a
human-only pre-flight block), and clear it from an item it moves to an auto-recoverable
blocked (blocked by a build-ready fix ticket) — that block self-heals and is not waiting on a
human.in_review/blocked → ticketed (PASS) or → blocked (FAIL), exactly
as the PRD intake does.done role but are
still natively open, per leaf-only-lifecycle.leaf-only-lifecycle state machine —
including an intermediate env value (On Dev/On Stg) when all required children have
reached that env — and close/complete/resolve it only when the derived env is the true
terminal done.ready role (a leaf-only-invariant
violation) by rolling it up from its children and removing the ready, with a
[lisa-repair-intake] audit note. This is the one ready-touching exception (see MUST NOT) and
applies only to containers, never to leaves.shipped and close/archive the source artifact
where the source vendor supports native close-out, per prd-lifecycle-rollup.It MUST NOT:
draft or verified (those are product-owned), or set verified itself.done value other than via the env-resolution rules, or close a native item at
any value other than the true terminal done (see leaf-only-lifecycle).ready leaves (that is lisa:intake's lane). A container carrying ready is the
documented exception above — repair-intake reconciles it because ready on a parent is an
invariant violation, not the human "claim this leaf" signal intake owns.blocked role(s), terminal/open
items, rollup parents/PRDs with child work, and containers carrying the ready role (a
leaf-only-invariant violation to reconcile), for the detected lifecycle(s), up to
max_candidates, via the Access layer reads.ready
containers, that need their derived state applied (status-only reconciliation, no native
close),blocked items whose dependencies are now cleared (safe, high-value, one-cycle wins),blocked items whose validation / quality-gate self-block now re-validates PASS —
a human filled in the missing sections (Class B; equally safe and high-value),blocked items with new clarifying answers,max_candidates cap. Continue after successful writes and after per-item errors."No stuck items actionable this cycle (examined N, all active or in backoff)."Process all materially actionable repairs among the enumerated candidates — scan up to
max_candidates, repair the actionable subset, then exit. This intentionally differs from
lisa:intake's one-ready-item claim contract because repair work is bounded by an explicit cap and
often consists of cheap close-out reconciliation that should drain in one cron pass.
Report outcomes in these buckets:
resumed — stalled in-progress work re-dispatched in place.resynced — a stalled build whose PR was merely behind its base, re-synced via
gh pr update-branch so the already-enabled auto-merge can land; the item stays claimed for a
later cycle to confirm the merge and transition.recovered — a stalled build whose PR had already merged, advanced by applying the env-resolved
claimed → done transition build-intake never got to (no re-dispatch).unblocked — blocker cleared (or answers resolved); re-dispatched or transitioned to
ticketed.closed_out — terminal-labeled items whose native open/active state was closed, completed,
resolved, or archived.rolled_up — parent/container/PRD rollups advanced to their derived state: an intermediate env
(e.g. all children at On Stg → parent On Stg), a fully-terminal close-out, or a stale-ready
container reconciled from its children.still_blocked — examined and intentionally left blocked, with the active reason.active — skipped because current work is not stale (or within backoff).errors — items that failed evaluation, with the error.State every item repaired this cycle and the action taken. If the output would be long, group by bucket and show compact refs plus counts.
/schedule "every 2 hours" /lisa:repair-intake https://www.notion.so/<workspace>/<database-id>
/schedule "every 2 hours" /lisa:repair-intake https://linear.app/acme
/schedule "every 2 hours" /lisa:repair-intake acme/product-prds
/schedule "every 2 hours" /lisa:repair-intake acme/frontend-v2 intake_mode=build
/schedule "every 2 hours" /lisa:repair-intake github intake_mode=both
/schedule "every 4 hours" /lisa:repair-intake SE stale_after=12h
/lisa:repair-intake SE stale_after=0 force=true # manual: treat all in-progress as stalled, ignore backoff
Run repair-intake less frequently than lisa:intake (the ready queue moves faster than
stuck work accumulates), or interleaved on a longer cadence.
ready — resume in place (decision tree).draft, verified) or set verified; PRD rollup close-out
may move open generated-work PRDs to shipped and close/archive them only after all associated
child work is terminal.done ONLY via the env-resolution rules, and trigger native closure only at the
true terminal done value (leaf-only-lifecycle).blocked build item's blocker may be a dependency, a validation/quality-gate self-block (no
dependency — re-check by re-running lisa:tracker-validate against current content), or an
ambiguity. Re-check every class present; do not treat "no is blocked by links" as "nothing to
do."blocked build item unless every parsed blocker is cleared (conservative
dependency clearing).max_candidates cap; default cap is 100.intake_mode is both when both PRD and build namespaces exist.[lisa-repair-intake] note within it
(unless force=true).lisa:intake is concurrently draining — the scheduling layer is
responsible for serialization.development
Use Expo DOM components to run web code in a webview on native and as-is on web. Migrate web code to native incrementally.
development
Guidelines for upgrading Expo SDK versions and fixing dependency issues
development
Use when implementing or debugging ANY network request, API call, or data fetching. Covers fetch API, React Query, SWR, error handling, caching, offline support, and Expo Router data loaders (`useLoaderData`).
tools
`@expo/ui/swift-ui` package lets you use SwiftUI Views and modifiers in your app.