Agent Skills
› omnigent-ai/omnigent
› feature-handoff
feature-handoff
GitHub用于生成结构化特性交接报告,包含模式、结果、需求、设计、用户旅程及测试覆盖等详细信息。
触发场景
完成特性开发后提交交接文档
进行代码审查后的修复与状态同步
安装
npx skills add omnigent-ai/omnigent --skill feature-handoff -g -y
SKILL.md
Frontmatter
{
"name": "feature-handoff",
"description": "Emit the complete feature handoff with exact modes, outcomes, CUJs, demos, and publication state."
}
The feature handoff
The last thing in your final message must be exactly one fenced ```json
block, with nothing after its closing fence. The caller reads the last valid
block, so an interim handoff right after opening the PR (with pr_url and a
provisional outcome) is fine; the final block supersedes it. Emit JSON, never
YAML, and include every key below, even when empty ("", []).
modeis exactly"authored_feature"or"review_remediation".outcomeis exactly one of"implemented","partially_implemented","not_implemented","nothing_to_build","needs_split", or"needs_more_info".
{
"feature_url": "https://linear.app/omnigent/issue/OMNI-1234",
"mode": "authored_feature",
"outcome": "implemented",
"feature_summary": "People can now rename a session from the session list instead of opening it first.",
"ticket_comment": "",
"proposed_children": [],
"requirements": [
"A session can be renamed from the session list",
"The new name appears everywhere the session is listed"
],
"design": {
"chosen": "Add a rename action to the list row that calls the existing session update API.",
"alternatives": [
{"option": "A separate rename dialog page", "rejected_because": "Adds navigation for a one-field edit."}
],
"risks": ["Concurrent renames: the last write wins, matching the existing update API."]
},
"cujs": [
{
"id": "CUJ-1",
"journey": "user opens the session list → chooses Rename on a row → types a name → the row shows the new name",
"surface": "web",
"covered": true,
"tests": ["tests/e2e_ui/sessions/test_rename_from_list.py::test_rename_from_list"],
"recordings": ["recordings/omni-1234/demo-cuj-1.mp4"],
"recording_blocker": "",
"manual_test": "",
"not_covered_reason": ""
},
{
"id": "CUJ-2",
"journey": "user renames a session from the mobile app",
"surface": "mobile",
"covered": false,
"tests": [],
"recordings": [],
"recording_blocker": "",
"manual_test": "",
"not_covered_reason": "The mobile list has no row actions yet; noted as a follow-up."
}
],
"recordings": [
{"cuj": "CUJ-1", "surface": "web", "path": "recordings/omni-1234/demo-cuj-1.mp4",
"format": "mp4", "capture_mode": "playwright_ui",
"caption": "open the session list → choose Rename → type a name → the row shows the new name"}
],
"files_changed": ["web/src/sessions/SessionRow.tsx"],
"tests": {"e2e": "tests/e2e_ui/sessions/test_rename_from_list.py", "added": []},
"test_audit": "CUJ-1 is covered by a new browser test because the rename crosses the browser boundary; it fails with the rename action removed.",
"impact_assessment": {
"base_sha": "<full target-branch tip SHA>",
"head_sha": "<full candidate HEAD SHA>",
"worktree_state": "clean",
"risks": [
{
"files": ["web/src/sessions/SessionRow.tsx"],
"behavior": "Row actions can change selection or navigation",
"consumers": ["session list", "session sidebar"],
"invariant": "Clicking a row still opens the session",
"check": "<exact command>",
"result": "passed",
"evidence": "<retained output reference, tested build and environment>"
}
],
"uncovered_boundaries": [],
"not_applicable_reason": ""
},
"remaining_work": [],
"pr_url": "https://github.com/omnigent-ai/omnigent/pull/4200",
"reviewed_pr_url": "",
"pushed_branch": "feat/omni-1234",
"ci_status": "green (all required checks pass)",
"polly_review": "clean on <full candidate HEAD SHA>",
"ocr_review": "clean on <full candidate HEAD SHA>: no findings",
"review_cycle": {
"head_sha": "<full candidate HEAD SHA>",
"fingerprint": "<fingerprint from the final review snapshot>",
"dispositions": [
{"key": "comment:<id>", "status": "addressed", "reason": "Fixed in <commit>; <test> passes."}
]
},
"ui_preview": "labeled ui-preview; preview at https://…",
"maintainer_review": "requested review from @<maintainer>",
"review_fingerprint": "",
"handled_review_ids": [],
"last_pushed_sha": "",
"session_id": "<this session id>"
}
Field meanings
outcome:implemented: every success condition in AGENTS.md holds, including the live Polly/OCR gate.partially_implemented: the feature is built and committed but something is missing, such as a blocked recording, an unresolved finding, failing CI, or, in local-only and workflow-owned runs, the publication and PR review you did not run. Name each gap inremaining_work.not_implemented: you tried and could not build it; explain why.nothing_to_build: already delivered; name the PR or commit.needs_split: stopped before building because the ticket is too big;ticket_commentandproposed_childrenare required.needs_more_info: stopped before building because the request is unclear, inputs or access are missing, or a design choice needs a human;ticket_commentgives the options and your recommendation.
feature_summary: plain English for a product user: what they can now do. No file names or CI details.ticket_comment/proposed_children: the comment the workflow posts on the ticket, and forneeds_spliteach child'stitle,description,cujs, anddepends_on(titles of earlier children). Empty otherwise.requirements,design,cujs: as written infeature-requirementsandfeature-design. Every covered CUJ lists at least one test and at least one recording path, or arecording_blockerplusmanual_test. Every not-covered CUJ has anot_covered_reason.recordings: one entry per declared clip, with the inspected captioned MP4 (or the guide's uncaptioned fallback) aspath.tests: committed checks as bare repository-relative paths or node IDs.e2eis the retained E2E path or"";addedlists the other selected checks. Put reasoning and gaps intest_audit.impact_assessment: asotto-impact-assessmentdescribes.pr_url,pushed_branch,ci_status,polly_review,ocr_review,review_cycle,ui_preview,maintainer_review: the publication state.review_cyclemust passreview_cycle.py checkforimplemented. A local-only (skip_push) run leavespr_urlempty, setspushed_branchto the committed local branch for a human to push, and lists publishing and the PR loop inremaining_work.reviewed_pr_url,review_fingerprint,handled_review_ids,last_pushed_sha: set inreview_remediationmode (withreviewed_pr_urlandpr_urlboth thereview_prURL); otherwise""or[]. In this mode,feature_urlcarries the PR's attached ticket, which the shared remediation skill callsbug_url.
版本历史
- 369359f 当前 2026-10-18 17:57


