plugins/lisa-copilot/skills/confluence-prd-intake/SKILL.md
Scans a Confluence space (or a parent page) for PRD pages currently parented under the configured `ready` lifecycle page and runs the first eligible one through the dry-run validation pipeline. A PRD that passes every gate gets tickets written and is re-parented under the `ticketed` lifecycle page; a PRD that fails gets clarifying-question comments and is re-parented under the `blocked` lifecycle page. Confluence counterpart of `lisa:notion-prd-intake` — the workflow is identical; only the source-of-truth tools and the state encoding differ (parent-page re-parenting instead of a status property). Composes existing skills (confluence-to-tracker, tracker-validate, tracker-source-artifacts, product-walkthrough).
npx skillsauth add codyswanngt/lisa confluence-prd-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.
All Atlassian operations in this skill go through lisa:atlassian-access. Do not call MCP tools or acli directly.
$ARGUMENTS is one of:
https://mycompany.atlassian.net/wiki/spaces/PRD or PRD.confluence.parents.ready page for this run (useful when an operator wants to target an alternative lifecycle parent). Example: https://mycompany.atlassian.net/wiki/spaces/PRD/pages/123456789/PRDs.confluence.parents.ready from .lisa.config.json as the scope.Run one intake cycle against the resolved ready lifecycle parent. Each direct child of that parent is treated as a PRD currently in the ready state. The first eligible PRD is claimed (re-parented to in_review), validated, routed to either the blocked parent (with clarifying comments) or the ticketed parent (with destination tickets created), then the cycle exits. Remaining ready PRDs stay queued for later scheduler invocations.
GitHub and Linear PRD lifecycles use labels (prd-ready / prd-in-review / etc.). Confluence does NOT — it uses parent pages instead. Scoped Atlassian API tokens (the only secure form Atlassian offers) cannot write Confluence labels via the v1 endpoint, and the v2 Label API group has no POST endpoint at all. Parent-id transitions, by contrast, are first-class in v2 and work with write:page:confluence scope. See config-resolution rule, section "Confluence PRD lifecycle uses parent pages, not labels," for the full rationale.
Lifecycle parent-page IDs are read from .lisa.config.json confluence.parents.*. Local overrides global per-key. Bash pattern:
# Read a lifecycle parent-page id by role. Local overrides global per-key.
read_parent_id() {
local role="$1"
local local_v global_v
local_v=$(jq -r ".confluence.parents.${role} // empty" .lisa.config.local.json 2>/dev/null)
global_v=$(jq -r ".confluence.parents.${role} // empty" .lisa.config.json 2>/dev/null)
echo "${local_v:-$global_v}"
}
READY_PARENT=$(read_parent_id ready)
IN_REVIEW_PARENT=$(read_parent_id in_review)
BLOCKED_PARENT=$(read_parent_id blocked)
TICKETED_PARENT=$(read_parent_id ticketed)
SHIPPED_PARENT=$(read_parent_id shipped)
DRAFT_PARENT=$(read_parent_id draft)
# Fail fast if any required role is unmapped — the lifecycle scaffolding hasn't been provisioned.
for role in ready in_review blocked ticketed; do
if [ -z "$(read_parent_id "$role")" ]; then
echo "Error: confluence.parents.${role} is not set in .lisa.config.json. Run /lisa:setup:confluence to provision the lifecycle parent pages." >&2
exit 1
fi
done
# Reverse-lookup: given a page's parentId, return which lifecycle role it currently occupies.
current_role_for_prd() {
local parent_id="$1"
for role in draft ready in_review blocked ticketed shipped; do
if [ "$(read_parent_id "$role")" = "$parent_id" ]; then
echo "$role"; return
fi
done
echo "unknown"
}
In prose below, the role names refer to the resolved parent-page IDs: e.g. "the ready parent" means whatever confluence.parents.ready resolves to.
This skill is the Confluence counterpart of lisa:notion-prd-intake, and shares its PRD shipped rollup phase (3f) with lisa:github-prd-intake and lisa:linear-prd-intake. The phases, gates, comment templates, and rules are identical — the only differences are (1) the lifecycle is encoded as parent-page placement instead of a status property, and (2) the fetch / comment / update tools route through lisa:atlassian-access. Keep all four intake skills behaviorally aligned: when changing intake logic — including the rollup phase — change them together.
The PRD shipped rollup phase (3f) re-parents a ticketed PRD to the shipped parent once all its generated top-level work is terminal, per the prd-lifecycle-rollup rule. This is the Confluence leg of the same vendor-neutral rollup that lisa:github-prd-intake implements for GitHub (LPC-1.3 #584); only the vendor surface (parent-page placement + documented generated-work section, since Confluence has no native ticket hierarchy) differs.
Do NOT ask the caller whether to proceed. Once invoked, run the cycle to completion for the first eligible PRD — claim, validate, branch to the blocked or ticketed parent, write the summary, and exit. The caller (a human or a cron) has already authorized the run by invoking the skill; re-prompting defeats the purpose of a background queue.
Specifically forbidden:
blocked parent. The blocked parent is a valid terminal state of this lifecycle, not a failure mode — routing a PRD there with gate-failure comments is exactly how this skill communicates "the PRD needs more work before it can be ticketed." That outcome is success.The only legitimate reasons to stop early:
atlassian.cloudId, confluence.parents.{ready,in_review,blocked,ticketed} in .lisa.config.json, E2E_BASE_URL, etc.). Surface the missing value and exit."No PRDs currently parented under the 'ready' lifecycle page. Nothing to do."The Confluence PRD lifecycle is encoded as parent-page placement — Confluence has no native status field, and scoped API tokens cannot write labels. Each lifecycle role corresponds to a dedicated parent page in the project's Confluence space:
draft → ready → in_review → blocked | ticketed → shipped → verified
(product) (us) (us) (product) (product)
(Each role corresponds to a dedicated parent page; the verified parent is resolved from confluence.parents.verified.)
verified is the terminal state after shipped: it means the shipped product has been empirically checked against the PRD (set by /lisa:verify-prd, not by this intake skill). A failed post-ship verification does not use blocked; /lisa:verify-prd re-parents the PRD shipped → ticketed and creates build-ready fix tickets that auto-build and trigger a re-verify (the self-healing loop), introducing no verifying / verification-failed parent. Like draft and shipped, verified is product-owned — this intake skill never re-parents a PRD into or out of the verified parent. See the "PRD-level verification vs ticket verification" section of the prd-lifecycle-rollup rule.
A PRD's current state is determined entirely by which lifecycle parent it sits under. Re-parenting is the transition.
This skill transitions:
ready → in_review (claim)in_review → blocked (gate failures or coverage gaps)in_review → ticketed (success)ticketed → blocked (post-write coverage gaps from Phase 3e)ticketed → shipped (PRD shipped rollup, Phase 3f — only when all generated top-level children are terminal)It never re-parents PRDs into or out of the draft or verified parents — those parents are owned by product (verified is set by /lisa:verify-prd after empirical PRD-level acceptance). The shipped parent is set by this skill's rollup phase (3f) when, and only when, the PRD's generated top-level work is all terminal — per the prd-lifecycle-rollup rule; product may also re-parent there by hand. Rollup never advances a PRD to shipped on partial completion, and never archives a PRD page at shipped. /lisa:verify-prd archives the page only after a verified PASS.
A "transition" means: update the PRD's parentId to the new role's parent-page id via lisa:atlassian-access operation: write-page payload: { id, parentId, title, version: { number: <next> } }. The v2 PUT endpoint requires the next version number and the page title in the payload; the body content is not strictly required for a re-parent-only edit, but some Atlassian deployments reject PUTs without a body. The skill MUST therefore GET the page first via read-page, capture title + current version + current body, then PUT with parentId swapped and version.number bumped — preserving body content is non-negotiable, this skill never edits PRD content. See transition_prd helper in Phase 3a for the canonical implementation.
If the project does not yet have the lifecycle parent pages provisioned, this skill cannot run. Provisioning is a one-time setup the project owner does (see "Adoption" at the bottom of this file).
$ARGUMENTS:
/wiki/spaces/<KEY>. (Used only as a sanity check that the operator's scope matches the configured space.)/pages/<ID>/...; use as the override for READY_PARENT for this run.confluence.parents.ready from config as READY_PARENT.lisa:atlassian-access operation: list-sites (it enforces connection match against .lisa.config.json).READY_PARENT is reachable: invoke lisa:atlassian-access operation: read-page id: $READY_PARENT and confirm it loads. If 404, surface a provisioning error and exit.Invoke lisa:atlassian-access operation: read-page-descendants id: $READY_PARENT and take the direct children (depth 1) of the ready lifecycle parent. Those are the PRDs currently in the ready state. Capture each child's id and title.
For each candidate, follow up with lisa:atlassian-access operation: read-page id: <PAGE-ID> and read its parentId to confirm it is still parented under $READY_PARENT (guards against eventual-consistency lag and concurrent re-parenting by another operator).
If the result set is empty, run a sanity probe across the other lifecycle parents to distinguish between a genuinely empty queue and a project where the lifecycle scaffolding is misconfigured:
IN_REVIEW_PARENT, BLOCKED_PARENT, TICKETED_PARENT: invoke read-page-descendants id: <parent> and count direct children."No PRDs found under any of the configured lifecycle parent pages (ready, in_review, blocked, ticketed). If this is a new project, move PRDs that are ready for ticketing under the configured 'ready' parent page (see Adoption section)." Exit with an error — this is a setup / migration issue, not a normal idle cycle.in_review, blocked, ticketed, or shipped). Exit cleanly with "No PRDs currently parented under the 'ready' lifecycle page. Nothing to do."Select the first ready PRD page returned by Phase 2 and process only that page. Later scheduler invocations process the remaining ready PRDs.
Transition the PRD from ready to in_review by re-parenting it:
# Pseudo-code; the actual call is a Skill tool invocation of lisa:atlassian-access.
#
# NOTE: the v2 PUT endpoint that backs write-page requires:
# - id
# - title (unchanged)
# - version.number (current + 1)
# - parentId (the new lifecycle parent)
# - body (some deployments reject PUTs without a body; preserving the body
# also matches this skill's invariant of never editing PRD content)
# We therefore GET-then-PUT: fetch via read-page to capture title, version,
# and body, then write-page with parentId swapped.
transition_prd() {
local prd_id="$1" target_role="$2"
local new_parent
new_parent=$(read_parent_id "$target_role")
# 1. read-page id: $prd_id -> capture title, version.number (=N), body.storage.value
# 2. write-page payload: {
# "id": "$prd_id",
# "title": "<unchanged>",
# "parentId": "$new_parent",
# "version": { "number": N+1 },
# "body": { "storage": { "value": "<unchanged>", "representation": "storage" } }
# }
}
# Claim:
transition_prd "$PRD_ID" in_review
This re-parent is the idempotency lock — a re-entrant cycle running concurrently won't see this PRD because read-page-descendants id: $READY_PARENT no longer includes it once parentId has moved.
If the update fails (permission error, version conflict / 409 race), log it and skip this PRD. Do not proceed to validation on a PRD you didn't successfully claim.
Invoke the lisa:confluence-to-tracker skill with dry_run: true and the PRD's URL. The skill returns a structured report containing:
This call also indirectly invokes lisa:tracker-source-artifacts (artifact extraction + classification) and lisa:product-walkthrough (when the PRD touches existing user-facing surfaces). All gate logic lives in lisa:tracker-validate, which lisa:confluence-to-tracker calls per ticket.
If PASS (every planned ticket passed every applicable gate):
lisa:confluence-to-tracker with dry_run: false to actually write the tickets. This re-runs Phases 1-5 and runs the preservation gate (Phase 5.5).lisa:atlassian-access operation: comment-page id: <PAGE-ID> kind: footer body: "..." listing the created tickets (epic, stories, sub-tasks) with their JIRA URLs. Lead with: "Ticketed by Claude. Created N JIRA issues — see below. Move this page under the 'shipped' lifecycle parent after the work is delivered."ticketed: transition_prd "$PRD_ID" ticketed.If FAIL (one or more planned tickets failed one or more gates):
The audience for these comments is the product team, not engineers. They are not familiar with JIRA gate IDs, validator vocabulary, or skill internals. Follow the rules below strictly — the goal is for a non-engineer product owner to read a comment, understand what is unclear, and know what to do next.
product_relevant = false. Those are internal data-quality problems — the agent should fix its own spec rather than ask product to clarify a missing core field. Record the dropped failures under Errors in the cycle summary so engineers can see them; never surface them on the PRD.prd_anchor (the inline-comment anchor from confluence-to-tracker's dry-run report). Failures that share an anchor become one comment thread on that block. Failures with prd_anchor: null are batched into one footer comment, since they have no source section to attach to.For each anchored group, invoke lisa:atlassian-access operation: comment-page kind: inline with:
id: the PRD page IDanchor: the prd_anchor value (the substring the inline comment will be attached to)body: the comment body, formatted using the template belowFor the unanchored group, post a single footer comment via lisa:atlassian-access operation: comment-page kind: footer body: "..." using the same template, prefixed with Issues without a specific section anchor: and one block per failure.
If the inline comment call returns "anchor not found" (the page text changed between fetch and post), fall back to a footer comment for that group via the same access skill operation. Do not silently drop the failure.
Each comment body MUST contain these four parts, in this order, no exceptions:
[<Category badge>] <prd_section heading text>
**What's unclear:** <validator's `what` field, verbatim — already product-readable>
**Recommendation:** <validator's `recommendation` field, verbatim — must contain 1–3 concrete options, never a generic "please clarify">
**Action:** Update this section in the PRD, then move the page back under the 'ready' lifecycle parent and Claude will re-run intake.
If multiple failures share an anchor, render each as its own **What's unclear:** ... **Recommendation:** ... block within the same comment, separated by horizontal lines (---). Keep the single [Category badge] heading at the top using the most-severe / most-blocking category from the group.
Use these exact badge labels — they are the validator's category values translated for product readers:
| Validator category | Badge label |
|---------------------|-------------|
| product-clarity | [Product clarity] |
| acceptance-criteria | [Acceptance criteria] |
| design-ux | [Design / UX] |
| scope | [Scope] |
| dependency | [Dependency] |
| data | [Data] |
| technical | [Technical] |
structural failures must never reach this step (filtered in 3c.1). If you see one here, treat it as an Error and surface internally.
S4, F2, etc.). Never appear in a comment body.lisa:tracker-validate, confluence-to-tracker).AC, OOS, repo, env var).recommendation is empty or vague, treat the failure as an Error and surface internally rather than posting a useless comment.After all comments are posted (anchored groups + the optional footer summary), re-parent the PRD to the blocked lifecycle parent: transition_prd "$PRD_ID" blocked. Do NOT write any destination tickets.
Stop immediately after the claimed PRD is ticketed, blocked, or recorded as an error.
ticketed)Per-ticket gates prove each ticket is well-formed; they do NOT prove the set of created tickets covers the whole PRD. Silent drops happen — invoke the lisa:prd-ticket-coverage skill to catch them.
Invoke lisa:prd-ticket-coverage with <PRD URL> tickets=[<created ticket keys from 3c step 2>]. The coverage skill auto-detects the PRD vendor from the URL.
Read the verdict:
| Verdict | Action |
|---------|--------|
| COMPLETE | Done. Leave PRD under ticketed parent. End the cycle. |
| COMPLETE_WITH_SCOPE_CREEP | Post an advisory footer comment naming the scope-creep tickets (so product can decide whether to close them as out-of-scope). Leave PRD under ticketed parent. |
| GAPS_FOUND | The created ticket set is incomplete. (a) For each gap, post a comment using the same product-facing template as Phase 3c.3 — inline-anchored when prd_anchor is non-null, footer otherwise; category badge from the gap's category field; What's unclear and Recommendation from the audit report's what and recommendation fields. Apply the same forbidden-language rules from Phase 3c.5. (b) Post one footer summary comment listing the tickets that were successfully created (so product knows what to keep vs. what to extend). (c) Re-parent the PRD from ticketed back to blocked: transition_prd "$PRD_ID" blocked. |
| NO_TICKETS_FOUND | Should not happen if step 2 succeeded. If it does, log it as an Error in the cycle summary and leave the PRD under ticketed with a comment flagging the audit failure for human review. |
The created tickets remain in the destination tracker regardless of the verdict — they are valid in their own right. The audit only tells us whether more are needed.
A PRD's lifecycle terminal state (shipped) is derived from whether the work it generated is done — it is never set by hand here on its own authority. This phase implements the Confluence leg of that derivation, per the prd-lifecycle-rollup rule (cite it by slug; do not restate its taxonomy or terminal-state semantics here). It is behaviorally identical to lisa:github-prd-intake's Phase 3f — only the vendor surface (parent-page re-parenting via lisa:atlassian-access + the documented generated-work section) differs from GitHub's (issue close + labels via gh).
Rollup runs over PRD pages that are already under the ticketed parent (the only state from which a PRD can ship): the freshly-ticketed PRD from Phase 3c, and — because rollup also catches PRDs whose children finished in a later cycle — every page currently parented under $TICKETED_PARENT. (Re-read its direct children via lisa:atlassian-access operation: read-page-descendants id: $TICKETED_PARENT.) Process each independently; one PRD never blocks another's rollup.
There is no archive configuration at the shipped hop. Rollup re-parents the PRD under $SHIPPED_PARENT and leaves the page active so Phase 3g can dispatch /lisa:verify-prd. Provider-native archival is owned by /lisa:verify-prd after it transitions the PRD to the verified parent on a PASS.
Rollup is keyed by the PRD's current state. If the PRD is already parented under $SHIPPED_PARENT, it is a no-op — do not re-parent, do not archive, do not re-comment. Record it as already shipped (no-op) in the cycle summary and move on. This is what makes re-running intake safe.
Read the PRD's generated top-level work — its created Epics and any top-level Stories created directly under it, excluding leaf Sub-tasks and any Story nested under a generated Epic (prd-lifecycle-rollup rule, generated-top-level-work contract). Confluence has no native ticket hierarchy, so the child set comes from the documented section only:
## Tickets section (primary and only source). Parse the machine-readable generated-work section lisa:prd-backlink writes to the PRD body (## Tickets, alias ## Generated Work; see #582) via lisa:atlassian-access operation: read-page id: <PRD-ID>. Top-level children are the ### <Epic key>: <title> group headers' first line (- [<ref>](<url>) — Epic) plus any top-level Story listed directly under ### Unparented items. Lines nested deeper ( - ... — Story: under an Epic, - ... — Sub-task:) are descendants, NOT top-level children — skip them.Dedupe the resulting child set by child-ref identity — the destination ticket ref recorded in each generated-work entry (the entry is keyed by that ref, not by list position) — per the prd-lifecycle-rollup idempotency dedupe key. If the section yields no child (the PRD generated nothing, or the relationship was never recorded), record no generated top-level children — rollup skipped and leave the PRD under $TICKETED_PARENT; do not ship an empty PRD.
For each top-level child, classify per the prd-lifecycle-rollup Confluence/Notion predicate:
leaf-only-lifecycle — read the child's own recorded state; do not re-derive it from its leaves here.The set of required children for the all-terminal check is the top-level children minus the terminal-but-dropped ones.
All required children terminal (every required top-level child is terminal; at least one required child exists):
shipped: transition_prd "$PRD_ID" shipped (GET-then-PUT via lisa:atlassian-access preserving the body verbatim). After the re-parent, re-read the page and confirm parentId matches $SHIPPED_PARENT (the single-parent invariant)./lisa:verify-prd; do not archive at the shipped hop.lisa:atlassian-access operation: comment-page kind: footer naming the terminal child set and (when dropped children exist) the dropped set, so the audit trail records why the PRD shipped. Lead with "Shipped by Claude — all generated top-level work is complete."Any required child incomplete / blocked:
$TICKETED_PARENT and leave the page active. Do NOT re-parent to shipped. Do NOT archive.- <ref> "<title>" — <state>), so product can see what's blocking the rollup. Keep it idempotent: regenerate the advisory rather than appending a fresh one each cycle.This phase implements exactly one PRD-lifecycle hop — ticketed → shipped — and deliberately leaves native archival to /lisa:verify-prd after the verified PASS. All terminal-state semantics, the generated-top-level-work boundary, and the dedupe-by-child-ref idempotency come from the prd-lifecycle-rollup rule; this skill is its Confluence implementation, not a second source of truth.
shipped and verified are distinct facts about a PRD (see the prd-lifecycle-rollup rule's "PRD-level verification vs ticket verification" and "Closing the loop" sections). Rollup (3f) only reaches the shipped parent; the shipped → verified (pass) / shipped → ticketed (fail) hops are owned by /lisa:verify-prd. This phase closes that loop by dispatching the initiative-level acceptance gate for shipped PRDs. It never performs the verification transition itself — the "never sets the verification outcome" invariant holds: lisa:verify-prd, not this skill, sets verified (or, on failure, re-opens the PRD to ticketed).
Re-query the PRDs currently parented under the shipped lifecycle parent via lisa:atlassian-access operation: read-page-descendants id: <confluence.parents.shipped>. Pick the first one and invoke lisa:verify-prd <page-url>. Process one shipped PRD per cycle — lisa:verify-prd is a heavy full flow (spec-conformance + empirical verification + fix-issue creation), so it is bounded exactly like the single-ready-PRD claim in Phase 3; the scheduler drains the rest.
Per-cycle combined bound: each scheduler cycle dispatches at most one ready PRD (the Phase 3 single-ready-PRD claim) and at most one shipped PRD for verification (this Phase 3g dispatch), for a maximum of two PRD operations per cycle. Ready intake runs first (Phase 3), then shipped verify (Phase 3g).
lisa:verify-prd owns the outcome: on a CONFORMS verdict with all empirical checks passing it transitions the PRD to the verified parent and posts evidence; on a conformance miss or a failing/unavailable check it re-parents the PRD shipped → ticketed (never the blocked parent) and creates build-ready fix tickets registered as the PRD's generated work, then posts a failure report — the fix tickets auto-build, rollup (3f) re-ships the PRD once they are terminal, and a later cycle re-verifies (the self-healing loop). Either branch moves the PRD out of the shipped parent, so it is not re-picked this cycle; a PRD whose generated work is not actually terminal is guard-stopped by lisa:verify-prd (left under shipped) — that is verify-prd's gate, not this skill's. This phase, like 3f, is behaviorally identical across all four intake skills (github-prd-intake, linear-prd-intake, notion-prd-intake, confluence-prd-intake) — only the $SHIPPED query surface differs; keep them aligned. Record the dispatched PRD + verify-prd's verdict in the summary.
After processing the single selected PRD, emit a summary:
## confluence-prd-intake summary
Scope: ready parent = <READY_PARENT> (<URL>)
Cycle started: <ISO timestamp>
Cycle completed: <ISO timestamp>
PRDs processed: <n>
- Ticketed: <n>
- <PRD title> → <epic-key> + <story-count> stories + <subtask-count> sub-tasks (coverage: COMPLETE | COMPLETE_WITH_SCOPE_CREEP)
- Blocked: <n>
- <PRD title> → <gate-failure-count> gate failures (pre-write) OR <gap-count> coverage gaps (post-write)
- Errors (claim failed, etc): <n>
- <PRD title> — <reason>
Total destination tickets created: <n>
Coverage audit summary: <n> COMPLETE / <n> COMPLETE_WITH_SCOPE_CREEP / <n> GAPS_FOUND
Print to the agent's output. Do not write this summary to Confluence or the destination tracker — it's an operational record for the human.
ready parent are picked up by later scheduler invocations.lisa:confluence-to-tracker (which delegates to lisa:tracker-write), and only ever re-parents PRDs among in_review, blocked, ticketed, and shipped (the last via the rollup phase 3f only) via lisa:atlassian-access operation: write-page. It never edits PRD body content, never re-parents into or out of draft, never archives pages at the shipped hop, and never deletes pages.in_review happens BEFORE validation runs, so a re-entrant call won't double-process.in_review if claim succeeded) — the human investigates from there.prd-* labels simultaneously) cannot occur here. After every transition, re-read the page and confirm parentId matches the expected role; if not, surface as an Error and skip.$SHIPPED_PARENT — no duplicate re-parent, no shipped-time archive, no duplicate comment. The all-terminal condition is a pure function of the children's current states (deduped by child-ref identity), so recomputing it is safe to re-run. Native archival only follows verified PASS in /lisa:verify-prd.Same configuration as lisa:confluence-to-tracker. See that skill for the full table. Key items:
.lisa.config.json: atlassian.cloudId (required), confluence.spaceKey and/or confluence.parentPageId (for breadth-of-scope sanity checks), and confluence.parents.{draft,ready,in_review,blocked,ticketed,shipped} for the lifecycle parent-page IDs.E2E_BASE_URL, E2E_TEST_PHONE, E2E_TEST_OTP, E2E_TEST_ORG, E2E_GRAPHQL_URL (operational E2E test config).Destination tracker config (jira / github / linear) is consumed by lisa:tracker-write internally — this skill does NOT read it. If any required value is missing, surface the missing key(s) and exit this cycle — never invent values.
| Field | Required | Purpose |
|-------|----------|---------|
| .lisa.config.json confluence.parents.ready | yes | Parent page id for "ready for ticketing" |
| .lisa.config.json confluence.parents.in_review | yes | Parent page id for "claimed by the agent" |
| .lisa.config.json confluence.parents.blocked | yes | Parent page id for "validation failure" |
| .lisa.config.json confluence.parents.ticketed | yes | Parent page id for "successfully ticketed" |
| .lisa.config.json confluence.parents.draft | recommended | Parent page id for PRDs still being drafted by product |
| .lisa.config.json confluence.parents.shipped | recommended | Parent page id the rollup phase (3f) re-parents delivered PRDs under; product may also use it by hand |
lisa:confluence-to-tracker → lisa:tracker-write. The validator's verdict gates progress; bypassing it produces broken tickets.in_review, blocked, ticketed, and shipped via the rollup phase only). Product owns draft and ready (as the entry signal); product and the rollup phase (3f) both re-parent under shipped.shipped only from the rollup phase, and only when all generated top-level children are terminal per the prd-lifecycle-rollup rule. Never ship on partial completion and never archive at shipped.write-page call preserves the body verbatim — fetch then PUT with body unchanged.prd_anchor group (or one footer summary for unanchored failures only). Comments must be inline-anchored where possible, categorized, plain-language, and contain a concrete recommendation.lisa:confluence-to-tracker returns errors, treat them as gate failures: comment + re-parent to blocked. Don't silently fail.Before this skill can run against a project, the project must adopt the lifecycle parent-page convention:
Draft, Ready, In Review, Blocked, Ticketed, Shipped. (Page titles are not significant — they exist to be re-parenting targets.).lisa.config.json under confluence.parents.<role>. /lisa:setup:confluence automates this.draft → ready when they are ready for ticketing (replaces the Notion Status = Ready flip).in_review, blocked, and ticketed parents for this skill — humans should not re-parent PRDs into them manually except to recover from an error.If the project hasn't adopted these parent pages, the first run exits with a provisioning error (not the idle empty-set message) — this distinguishes a setup issue from a genuinely empty queue so operators know to run /lisa:setup:confluence rather than assuming there is no work. See Phase 2 for how the skill detects this case.
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.