plugins/src/base/skills/github-project-v2/SKILL.md
Shared GitHub ProjectV2 coordination utility. Every GitHub writer or linked pull request flow that needs Project membership MUST delegate through this skill instead of inlining GraphQL. Resolves the configured ProjectV2 id from `github.projects.v2`, validates namespace + access, adds Issue or Pull Request node ids to the Project, optionally updates Project field values, and returns exact failures with best-effort vs required-mode branching.
npx skillsauth add codyswanngt/lisa github-project-v2Install 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.
Single chokepoint for GitHub ProjectV2 coordination. Caller skills (github-write-prd,
github-write-issue, git-submit-pr, later linked-PR flows, later doctor/setup checks) MUST go through
this skill rather than duplicating gh api graphql calls.
The utility never invents policy. It applies the config + validation contract already defined in
config-resolution:
github.projects.v2 absent → coordination is disabled; callers keep repository-local writes.required: false → Project failures are warning-level, and the underlying issue / PR write
remains the durable success.required: true → the same Project failures are blocking errors.The caller passes exactly one operation plus its arguments:
operation: resolve-project
operation: add-item content_node_id: <issue-or-pr-node-id>
operation: ensure-item content_node_id: <issue-or-pr-node-id>
operation: update-fields item_id: <project-item-id> values: [{ field: "Status", option: "In Progress" }]
operation: add-and-update content_node_id: <issue-or-pr-node-id> values: [{ field: "Repository", text: "frontend-v2" }]
Argument rules:
content_node_id is the opaque GraphQL node id of a real GitHub Issue or Pull Request.item_id is the opaque Project item id returned by add-item / ensure-item.values is optional for update-fields / add-and-update. Omit it when membership alone is
sufficient.Return shape:
enabled: true | false
required: true | false
outcome: disabled | resolved | added | reused | updated | warning | blocked
project_id: "<opaque-project-id>"
item_id: "<opaque-project-item-id>"
warnings:
- "<warning text>"
error:
code: "<stable-code>"
message: "<exact gh / GraphQL failure>"
remediation: "<next step>"
error.message MUST preserve the exact GitHub failure text (permission error, missing project,
field mismatch, duplicate-content response, etc.). Do not collapse failures into generic
"Project update failed."
Read config in local-overrides-first order:
read_cfg() {
local path="$1"
local lv gv
lv=$(jq -r "$path // empty" .lisa.config.local.json 2>/dev/null)
gv=$(jq -r "$path // empty" .lisa.config.json 2>/dev/null)
echo "${lv:-$gv}"
}
ORG=$(read_cfg '.github.org')
REPO=$(read_cfg '.github.repo')
OWNER_KIND=$(read_cfg '.github.projects.v2.owner.kind')
OWNER_SLUG=$(read_cfg '.github.projects.v2.owner.slug')
PROJECT_NUMBER=$(read_cfg '.github.projects.v2.number')
REQUIRED=$(read_cfg '.github.projects.v2.required')
REQUIRED=${REQUIRED:-false}
If the github.projects.v2 block is absent or incomplete, return:
enabled: false
required: false
outcome: disabled
That is a clean no-op for best-effort callers; they continue the repository-local write path.
When the block is present:
github.org, github.repo, owner.kind, owner.slug, and number.owner.slug MUST equal github.org.organization or user.gh auth status succeeds before any GraphQL call.Namespace mismatch is never silent. It returns a configuration failure with exact remediation:
enabled: true
required: <required>
outcome: warning | blocked
error:
code: project_namespace_mismatch
message: "github.projects.v2.owner.slug must match github.org in v1"
remediation: "Use a Project owned by <github.org> or remove github.projects.v2."
Resolve the human-facing owner + number to the opaque ProjectV2 id:
gh api graphql -f query='
query($login:String!,$number:Int!){
organization(login:$login){ projectV2(number:$number){ id title number url } }
user(login:$login){ projectV2(number:$number){ id title number url } }
}' -F login="$OWNER_SLUG" -F number="$PROJECT_NUMBER"
Pick the branch matching owner.kind. If the Project is missing, inaccessible, or the authenticated
identity cannot read it, preserve the exact GraphQL failure text in error.message.
Successful resolution returns:
enabled: true
required: <required>
outcome: resolved
project_id: "<opaque-project-id>"
For add-item, ensure-item, or add-and-update, first resolve the Project id, then add the
provided Issue / Pull Request node id:
gh api graphql -f query='
mutation($projectId:ID!,$contentId:ID!){
addProjectV2ItemById(input:{projectId:$projectId contentId:$contentId}){
item { id }
}
}' -F projectId="$PROJECT_ID" -F contentId="$CONTENT_NODE_ID"
Behavior:
add-item expects the membership write to succeed and returns outcome: added.ensure-item is idempotent. If GitHub reports the content is already in the Project, return
outcome: reused and surface the existing membership as a success, not a failure.add-and-update adds first, then continues into Step 4.When GitHub returns a duplicate-membership or already-present response, ensure-item MUST branch
idempotently rather than rethrowing.
If values are provided, apply them in order to the Project item returned from Step 3. Support the
common field types callers need first:
The utility resolves the Project's fields first, then performs the correct GraphQL mutation for the typed value. Missing field names or option names are exact failures; never silently skip them.
Example shape:
operation: add-and-update
content_node_id: <node-id>
values:
- { field: "Status", option: "In Progress" }
- { field: "Repository", text: "lisa" }
Successful field updates return outcome: updated with both project_id and item_id.
Every failure after config detection branches on required:
required: false → return outcome: warning, preserve the exact error, and let the caller
keep the underlying issue / PR write as the durable success.required: true → return outcome: blocked with the same exact error, causing the caller to
fail the write before claiming Project coordination succeeded.This means the exact same GitHub failure can surface in two different severities without changing its message:
enabled: true
required: false
outcome: warning
error:
code: project_access_denied
message: "Resource not accessible by integration"
remediation: "Grant the token Project read/write access or disable github.projects.v2."
enabled: true
required: true
outcome: blocked
error:
code: project_access_denied
message: "Resource not accessible by integration"
remediation: "Grant the token Project read/write access or disable github.projects.v2."
ensure-item.documentation
Onboard a user to the project via its LLM Wiki. Interviews the user about themselves in relation to the project, captures that to project-scoped memory only, then gives a guided tour of what the project is and sample questions they can ask. Use when someone is new to the project or asks to be onboarded. Read-mostly — it does not open PRs or write PII into the wiki.
documentation
Migrate an existing, hand-rolled wiki implementation onto the lisa-wiki kernel — phased and compatibility-first, with a strict no-loss guarantee. Use when adopting lisa-wiki in a repo that already has its own wiki/, ingest skills, docs, or roles. Renaming things into the canonical shape is fine; losing functionality or data is not. Ends by running /doctor.
development
Health-check the LLM Wiki. Reports orphan pages, contradictions, stale claims, broken internal links, missing index/log coverage, structure-manifest violations, and secret/tenant leaks. Use periodically or before hardening a wiki. Read-only — it reports findings, it does not fix them.
testing
Ingest source material into the LLM Wiki. With an argument (URL, file path, or prompt) it ingests that one source; with no argument it runs a full ingest across every enabled non-external-write source. Routes to the right connector, then runs the ordered pipeline (source note → synthesis → index → log → verify → state → commit/PR). Use whenever new knowledge should enter the wiki.