@flydocs/cli 0.6.0-alpha.4 → 0.6.0-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/cli.js +12 -16
  2. package/package.json +1 -1
  3. package/template/.claude/CLAUDE.md +11 -9
  4. package/template/.claude/commands/flydocs-setup.md +34 -19
  5. package/template/.claude/commands/knowledge.md +61 -0
  6. package/template/.claude/skills/flydocs-cloud/SKILL.md +43 -36
  7. package/template/.claude/skills/flydocs-cloud/scripts/create_issue.py +19 -2
  8. package/template/.claude/skills/flydocs-cloud/scripts/create_team.py +3 -3
  9. package/template/.claude/skills/flydocs-cloud/scripts/delete_milestone.py +21 -0
  10. package/template/.claude/skills/flydocs-cloud/scripts/estimate.py +9 -5
  11. package/template/.claude/skills/flydocs-cloud/scripts/flydocs_api.py +4 -0
  12. package/template/.claude/skills/flydocs-cloud/scripts/get_estimate_scale.py +23 -0
  13. package/template/.claude/skills/flydocs-cloud/scripts/list_teams.py +1 -1
  14. package/template/.claude/skills/flydocs-cloud/scripts/refresh_labels.py +87 -0
  15. package/template/.claude/skills/flydocs-cloud/scripts/set_identity.py +38 -0
  16. package/template/.claude/skills/flydocs-cloud/scripts/set_preferences.py +49 -0
  17. package/template/.claude/skills/flydocs-cloud/scripts/set_team.py +5 -4
  18. package/template/.claude/skills/flydocs-cloud/scripts/update_issue.py +22 -4
  19. package/template/.claude/skills/flydocs-cloud/scripts/update_milestone.py +42 -0
  20. package/template/.claude/skills/flydocs-workflow/SKILL.md +23 -18
  21. package/template/.claude/skills/flydocs-workflow/reference/comment-templates.md +1 -0
  22. package/template/.claude/skills/flydocs-workflow/reference/pr-workflow.md +105 -0
  23. package/template/.claude/skills/flydocs-workflow/reference/priority-estimates.md +37 -15
  24. package/template/.claude/skills/flydocs-workflow/session.md +24 -16
  25. package/template/.claude/skills/flydocs-workflow/stages/capture.md +8 -3
  26. package/template/.claude/skills/flydocs-workflow/stages/close.md +4 -3
  27. package/template/.claude/skills/flydocs-workflow/stages/implement.md +28 -4
  28. package/template/.claude/skills/flydocs-workflow/stages/refine.md +20 -4
  29. package/template/.claude/skills/flydocs-workflow/stages/review.md +14 -2
  30. package/template/.flydocs/config.json +2 -2
  31. package/template/.flydocs/version +1 -1
  32. package/template/AGENTS.md +8 -8
  33. package/template/flydocs/knowledge/INDEX.md +38 -53
  34. package/template/flydocs/knowledge/README.md +60 -9
  35. package/template/flydocs/knowledge/templates/decision.md +47 -0
  36. package/template/flydocs/knowledge/templates/feature.md +35 -0
  37. package/template/flydocs/knowledge/templates/note.md +25 -0
  38. package/template/manifest.json +8 -2
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env python3
2
+ """Refresh label config from the relay — validates and updates local config.
3
+
4
+ Fetches current team labels from the relay, compares against local config,
5
+ and reports any stale or missing label IDs. With --fix, updates local config
6
+ to match the relay's current state.
7
+ """
8
+
9
+ import json
10
+ import sys
11
+ from pathlib import Path
12
+
13
+ sys.path.insert(0, str(Path(__file__).parent))
14
+ from flydocs_api import get_client, output_json, fail
15
+
16
+
17
+ def main():
18
+ fix_mode = "--fix" in sys.argv
19
+
20
+ client = get_client()
21
+
22
+ # Fetch current labels from relay
23
+ labels = client.get("/labels")
24
+ label_map = {l["id"]: l["name"] for l in labels}
25
+ label_by_name = {l["name"].lower(): l["id"] for l in labels}
26
+
27
+ # Load local config
28
+ config_path = client.config_path
29
+ if not config_path.exists():
30
+ fail("No .flydocs/config.json found")
31
+
32
+ with open(config_path, "r") as f:
33
+ config = json.load(f)
34
+
35
+ issue_labels = config.get("issueLabels", {})
36
+ stale: list[dict] = []
37
+ valid: list[dict] = []
38
+
39
+ # Check each label ID in config against relay
40
+ for category, entries in issue_labels.items():
41
+ if isinstance(entries, dict):
42
+ for key, label_id in entries.items():
43
+ if label_id in label_map:
44
+ valid.append({"category": category, "key": key, "id": label_id, "name": label_map[label_id]})
45
+ else:
46
+ # Try to find by key name
47
+ resolved = label_by_name.get(key.lower())
48
+ stale.append({
49
+ "category": category,
50
+ "key": key,
51
+ "staleId": label_id,
52
+ "resolvedId": resolved,
53
+ "resolvedName": key if resolved else None,
54
+ })
55
+
56
+ if fix_mode and stale:
57
+ # Update stale IDs in config
58
+ fixed = 0
59
+ for item in stale:
60
+ if item["resolvedId"]:
61
+ issue_labels[item["category"]][item["key"]] = item["resolvedId"]
62
+ fixed += 1
63
+
64
+ with open(config_path, "w") as f:
65
+ json.dump(config, f, indent=2)
66
+ f.write("\n")
67
+
68
+ output_json({
69
+ "success": True,
70
+ "valid": len(valid),
71
+ "stale": len(stale),
72
+ "fixed": fixed,
73
+ "unfixable": len(stale) - fixed,
74
+ "details": stale,
75
+ })
76
+ else:
77
+ output_json({
78
+ "valid": len(valid),
79
+ "stale": len(stale),
80
+ "totalProviderLabels": len(labels),
81
+ "details": stale if stale else "All label IDs are current",
82
+ "hint": "Run with --fix to update stale IDs" if stale else None,
83
+ })
84
+
85
+
86
+ if __name__ == "__main__":
87
+ main()
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env python3
2
+ """Set provider identity via the FlyDocs Relay API.
3
+
4
+ Binds the user's provider-specific ID to their FlyDocs user record.
5
+ Once set, ?mine=true resolves via exact provider ID matching.
6
+ """
7
+
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ sys.path.insert(0, str(Path(__file__).parent))
12
+ from flydocs_api import get_client, output_json, fail
13
+
14
+ VALID_PROVIDERS = ("linear", "jira", "gitlab")
15
+
16
+ if len(sys.argv) < 3:
17
+ fail(f"Usage: set_identity.py <provider> <provider-user-id>\n Providers: {', '.join(VALID_PROVIDERS)}")
18
+
19
+ provider = sys.argv[1].lower()
20
+ provider_id = sys.argv[2]
21
+
22
+ if provider not in VALID_PROVIDERS:
23
+ fail(f"Invalid provider: {provider}. Must be one of: {', '.join(VALID_PROVIDERS)}")
24
+
25
+ if not provider_id:
26
+ fail("Provider user ID cannot be empty")
27
+
28
+ client = get_client()
29
+ result = client.post("/auth/identity", {
30
+ "provider": provider,
31
+ "providerId": provider_id,
32
+ })
33
+
34
+ output_json({
35
+ "success": result.get("success", True),
36
+ "provider": result.get("provider", provider),
37
+ "providerId": result.get("providerId", provider_id),
38
+ })
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env python3
2
+ """Get or set user preferences via the FlyDocs Relay API.
3
+
4
+ With no arguments, returns current preferences (GET).
5
+ With flags, updates preferences (POST).
6
+ """
7
+
8
+ import argparse
9
+ import sys
10
+ from pathlib import Path
11
+
12
+ sys.path.insert(0, str(Path(__file__).parent))
13
+ from flydocs_api import get_client, output_json, fail
14
+
15
+
16
+ def main():
17
+ parser = argparse.ArgumentParser(description="Get or set user preferences")
18
+ parser.add_argument("--workspace", default=None, help="Default workspace ID")
19
+ parser.add_argument("--assignee", default=None, help="Default assignee ('self' or user ID)")
20
+ parser.add_argument("--display", default=None, help="Display preferences (JSON string)")
21
+ args = parser.parse_args()
22
+
23
+ client = get_client()
24
+
25
+ # If no flags provided, GET current preferences
26
+ if args.workspace is None and args.assignee is None and args.display is None:
27
+ result = client.get("/auth/preferences")
28
+ output_json(result)
29
+ return
30
+
31
+ # Build update body from provided flags
32
+ body: dict = {}
33
+ if args.workspace is not None:
34
+ body["defaultWorkspaceId"] = args.workspace
35
+ if args.assignee is not None:
36
+ body["defaultAssignee"] = args.assignee
37
+ if args.display is not None:
38
+ body["displayPreferences"] = args.display
39
+
40
+ result = client.post("/auth/preferences", body)
41
+
42
+ output_json({
43
+ "success": result.get("success", True),
44
+ "preferences": result.get("preferences", body),
45
+ })
46
+
47
+
48
+ if __name__ == "__main__":
49
+ main()
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env python3
2
- """Set team preference via the FlyDocs Relay API.
2
+ """Set team/project preference via the FlyDocs Relay API.
3
3
 
4
4
  Stores the team preference on the relay (for server-side scoping)
5
5
  and updates the local config (for display/reference).
6
+ For Jira, this sets the active Jira project.
6
7
  """
7
8
 
8
9
  import argparse
@@ -15,8 +16,8 @@ from flydocs_api import get_client, output_json, fail
15
16
 
16
17
 
17
18
  def main():
18
- parser = argparse.ArgumentParser(description="Set team preference")
19
- parser.add_argument("team_id", help="Linear team UUID")
19
+ parser = argparse.ArgumentParser(description="Set team or project preference")
20
+ parser.add_argument("team_id", help="Provider team/workspace UUID")
20
21
  args = parser.parse_args()
21
22
 
22
23
  client = get_client()
@@ -28,7 +29,7 @@ def main():
28
29
  with open(config_path, "r") as f:
29
30
  config = json.load(f)
30
31
  if "provider" not in config:
31
- config["provider"] = {"type": "linear", "teamId": None}
32
+ config["provider"] = {"type": None, "teamId": None}
32
33
  config["provider"]["teamId"] = args.team_id
33
34
  with open(config_path, "w") as f:
34
35
  json.dump(config, f, indent=2)
@@ -13,13 +13,14 @@ def main():
13
13
  parser = argparse.ArgumentParser(description="Update issue fields")
14
14
  parser.add_argument("ref", help="Issue reference (e.g., ENG-123)")
15
15
  parser.add_argument("--title", default=None)
16
- parser.add_argument("--priority", type=int, choices=range(5))
17
- parser.add_argument("--estimate", type=int, choices=range(1, 6))
16
+ parser.add_argument("--priority", type=int, help="Priority (0-4, relay translates per provider)")
17
+ parser.add_argument("--estimate", type=int, help="Estimate points (relay translates per provider)")
18
18
  parser.add_argument("--assignee", default=None)
19
19
  parser.add_argument("--state", default=None)
20
20
  parser.add_argument("--description", default=None)
21
21
  parser.add_argument("--description-file", default=None)
22
22
  parser.add_argument("--labels", default=None, help="Comma-separated label names")
23
+ parser.add_argument("--milestone", default=None, help="Milestone ID or name (resolved by name lookup)")
23
24
  parser.add_argument("--comment", default=None)
24
25
  args = parser.parse_args()
25
26
 
@@ -65,10 +66,27 @@ def main():
65
66
  body["comment"] = args.comment
66
67
  updated_fields.append("comment")
67
68
 
68
- if not body:
69
- fail("No fields to update. Use --title, --priority, --estimate, --assignee, --state, --description, --labels, or --comment")
69
+ if not body and args.milestone is None:
70
+ fail("No fields to update. Use --title, --priority, --estimate, --assignee, --state, --description, --labels, --milestone, or --comment")
70
71
 
71
72
  client = get_client()
73
+
74
+ if args.milestone is not None:
75
+ milestone_id = args.milestone
76
+ # If it doesn't look like a UUID, resolve by name
77
+ if len(milestone_id) != 36 or "-" not in milestone_id:
78
+ milestones = client.get("/milestones")
79
+ match = None
80
+ for m in milestones:
81
+ if m["name"].lower() == milestone_id.lower():
82
+ match = m
83
+ break
84
+ if not match:
85
+ fail(f"Milestone not found: {milestone_id}")
86
+ milestone_id = match["id"]
87
+ body["milestoneId"] = milestone_id
88
+ updated_fields.append("milestone")
89
+
72
90
  result = client.patch(f"/issues/{args.ref}", body)
73
91
 
74
92
  output_json({
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env python3
2
+ """Update a milestone via the FlyDocs Relay API."""
3
+
4
+ import argparse
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ sys.path.insert(0, str(Path(__file__).parent))
9
+ from flydocs_api import get_client, output_json, fail
10
+
11
+
12
+ def main():
13
+ parser = argparse.ArgumentParser(description="Update milestone")
14
+ parser.add_argument("milestone_id", help="Milestone UUID")
15
+ parser.add_argument("--name", default=None)
16
+ parser.add_argument("--target-date", default=None, dest="target_date")
17
+ parser.add_argument("--description", default=None)
18
+ args = parser.parse_args()
19
+
20
+ body: dict = {}
21
+ if args.name is not None:
22
+ body["name"] = args.name
23
+ if args.target_date is not None:
24
+ body["targetDate"] = args.target_date
25
+ if args.description is not None:
26
+ body["description"] = args.description
27
+
28
+ if not body:
29
+ fail("No fields to update. Use --name, --target-date, or --description")
30
+
31
+ client = get_client()
32
+ result = client.patch(f"/milestones/{args.milestone_id}", body)
33
+
34
+ output_json({
35
+ "success": result.get("success", True),
36
+ "id": result.get("id", args.milestone_id),
37
+ "name": result.get("name", args.name),
38
+ })
39
+
40
+
41
+ if __name__ == "__main__":
42
+ main()
@@ -17,6 +17,10 @@ triggers:
17
17
  - transition
18
18
  - status
19
19
  - issue
20
+ - knowledge
21
+ - document
22
+ - PR
23
+ - pull request
20
24
  ---
21
25
 
22
26
  # FlyDocs Workflow
@@ -35,32 +39,33 @@ Capture → Refine → Activate → Implement → Review → Validate → Close
35
39
 
36
40
  ## Stage Index
37
41
 
38
- | Stage | File | Intent | Agent |
39
- |-------|------|--------|-------|
40
- | Capture | stages/capture.md | Create issue from input | PM |
41
- | Refine | stages/refine.md | Triage + spec completion | PM |
42
- | Activate | stages/activate.md | Assign + start work | PM |
43
- | Implement | stages/implement.md | Build + test + simplify | Implementation |
44
- | Review | stages/review.md | Code quality validation | Review |
45
- | Validate | stages/validate.md | User acceptance testing | QE |
46
- | Close | stages/close.md | Archive completed work | PM |
42
+ | Stage | File | Intent | Agent |
43
+ | --------- | ------------------- | ------------------------ | -------------- |
44
+ | Capture | stages/capture.md | Create issue from input | PM |
45
+ | Refine | stages/refine.md | Triage + spec completion | PM |
46
+ | Activate | stages/activate.md | Assign + start work | PM |
47
+ | Implement | stages/implement.md | Build + test + simplify | Implementation |
48
+ | Review | stages/review.md | Code quality validation | Review |
49
+ | Validate | stages/validate.md | User acceptance testing | QE |
50
+ | Close | stages/close.md | Archive completed work | PM |
47
51
 
48
52
  ## Session
49
53
 
50
- | Action | File |
51
- |--------|------|
52
- | Start session | session.md |
53
- | Wrap session | session.md |
54
+ | Action | File |
55
+ | --------------- | ---------- |
56
+ | Start session | session.md |
57
+ | Wrap session | session.md |
54
58
  | Stale detection | session.md |
55
59
 
56
60
  ## Reference
57
61
 
58
- | Topic | File |
59
- |-------|------|
60
- | Comment templates | reference/comment-templates.md |
61
- | Status transitions | reference/status-workflow.md |
62
+ | Topic | File |
63
+ | -------------------- | ------------------------------- |
64
+ | Comment templates | reference/comment-templates.md |
65
+ | Status transitions | reference/status-workflow.md |
62
66
  | Priority & estimates | reference/priority-estimates.md |
63
- | Golden rules | reference/golden-rules.md |
67
+ | PR & git workflow | reference/pr-workflow.md |
68
+ | Golden rules | reference/golden-rules.md |
64
69
 
65
70
  ## Templates
66
71
 
@@ -56,6 +56,7 @@ Canonical templates for all workflow transitions. Copy exactly, fill bracketed v
56
56
  **Files:** [count] modified
57
57
  **Testing:** [How it was verified]
58
58
  **Criteria:** [X]/[Y] complete
59
+ **PR:** [link or "direct commit"]
59
60
  ```
60
61
 
61
62
  ## Code Review Passed
@@ -0,0 +1,105 @@
1
+ # PR & Git Workflow
2
+
3
+ ## Branch Naming
4
+
5
+ Format: `<type>/<ref>-<slug>`
6
+
7
+ | Type | When |
8
+ | --------- | -------------------------------------- |
9
+ | `feature` | New functionality |
10
+ | `fix` | Bug fixes |
11
+ | `chore` | Maintenance, refactoring, dependencies |
12
+ | `docs` | Documentation only |
13
+
14
+ Examples:
15
+
16
+ - `feature/FLY-255-knowledge-capture`
17
+ - `fix/FLY-301-login-timeout`
18
+ - `chore/FLY-290-upgrade-deps`
19
+
20
+ Keep the slug short (2-4 words, kebab-case). Include the issue reference.
21
+
22
+ ## Commit Messages
23
+
24
+ Format: `<type>: <description> (<ref>)`
25
+
26
+ - Lead with what changed, not how
27
+ - Use imperative mood ("Add", not "Added")
28
+ - Keep the first line under 72 characters
29
+ - Add a body for non-obvious changes
30
+
31
+ Examples:
32
+
33
+ ```
34
+ feat: Add knowledge doc templates and /knowledge command (FLY-255)
35
+ fix: Handle null milestone in create_issue response (FLY-301)
36
+ chore: Remove deprecated auth middleware (FLY-290)
37
+ ```
38
+
39
+ ## When to Create a PR
40
+
41
+ **Create a PR when:**
42
+
43
+ - Changes affect shared code (not just local config or docs)
44
+ - Multiple files changed across different concerns
45
+ - Changes need review before merging
46
+ - Working on a branch (not committing directly to main)
47
+
48
+ **Commit directly when:**
49
+
50
+ - Single-file documentation updates
51
+ - Config changes for local development
52
+ - Trivial fixes (typos, formatting)
53
+ - The user explicitly requests direct commit
54
+
55
+ When in doubt, create a PR. It's easier to merge a PR than to revert a direct commit.
56
+
57
+ ## PR Description Template
58
+
59
+ ```markdown
60
+ ## Summary
61
+
62
+ [1-3 bullet points describing what changed and why]
63
+
64
+ Closes [ISSUE-REF]
65
+
66
+ ## Changes
67
+
68
+ - [Key change 1]
69
+ - [Key change 2]
70
+ - [Key change 3]
71
+
72
+ ## Test Plan
73
+
74
+ - [ ] [How to verify change 1]
75
+ - [ ] [How to verify change 2]
76
+
77
+ ## Notes
78
+
79
+ [Anything reviewers should know — tradeoffs, follow-up work, decisions made]
80
+ ```
81
+
82
+ ## PR Workflow in Practice
83
+
84
+ ### During Implement Stage
85
+
86
+ After self-review (step 7 in `implement.md`), before handing off to review:
87
+
88
+ 1. Create branch: `git checkout -b <type>/<ref>-<slug>`
89
+ 2. Stage and commit changes with a descriptive message
90
+ 3. Push branch: `git push -u origin <branch>`
91
+ 4. Create PR with the template above, linking the issue
92
+ 5. Include the PR link in the "Ready for Review" comment
93
+
94
+ ### During Review Stage
95
+
96
+ The reviewer should:
97
+
98
+ - Review the PR diff (not just local git diff)
99
+ - Leave comments on the PR for specific code feedback
100
+ - Reference the PR in review comments on the issue
101
+
102
+ ### After Review
103
+
104
+ - **Approved**: Merge the PR, then transition issue to Testing
105
+ - **Changes needed**: Push fixes to the same branch, re-request review
@@ -2,27 +2,49 @@
2
2
 
3
3
  ## Priority Values
4
4
 
5
- | Value | Name | Use When |
6
- |-------|------|----------|
7
- | 0 | None | Not yet triaged |
8
- | 1 | Urgent | Drop everything, fix now |
9
- | 2 | High | Next up, unblocks others |
10
- | 3 | Medium | Normal priority (default) |
11
- | 4 | Low | Nice to have |
5
+ | Value | Name | Use When |
6
+ | ----- | ------ | ------------------------- |
7
+ | 0 | None | Not yet triaged |
8
+ | 1 | Urgent | Drop everything, fix now |
9
+ | 2 | High | Next up, unblocks others |
10
+ | 3 | Medium | Normal priority (default) |
11
+ | 4 | Low | Nice to have |
12
12
 
13
13
  ## Estimate Values (Complexity)
14
14
 
15
- | Value | Name | Rough Effort |
16
- |-------|------|--------------|
17
- | 1 | XS | < 1 hour |
18
- | 2 | S | 1-4 hours |
19
- | 3 | M | Half day to full day |
20
- | 4 | L | 2-3 days |
21
- | 5 | XL | Week+ |
15
+ | Value | Name | Rough Effort |
16
+ | ----- | ---- | -------------------- |
17
+ | 1 | XS | < 1 hour |
18
+ | 2 | S | 1-4 hours |
19
+ | 3 | M | Half day to full day |
20
+ | 4 | L | 2-3 days |
21
+ | 5 | XL | Week+ |
22
22
 
23
23
  ## Guidance
24
24
 
25
25
  - Set priority during Refine or Activate stages
26
26
  - Set estimate during Refine stage (before Ready)
27
27
  - If estimate is missing at Activate, set it before transitioning
28
- - XL estimates often indicate the issue should be broken into smaller pieces
28
+ - Estimate values may vary by provider the relay translates per provider configuration
29
+
30
+ ## Decomposition
31
+
32
+ When an estimate is large (XL / 5+ or provider equivalent), prompt for decomposition:
33
+
34
+ 1. **Identify natural boundaries** — separate concerns, independent deliverables, sequential phases
35
+ 2. **Create child issues** — each should be independently estimable at M or smaller
36
+ 3. **Link parent to children** — use `link.py` with type `blocks` (parent blocks children conceptually)
37
+ 4. **Re-estimate parent** — set to 0 or remove estimate, since children carry the work
38
+ 5. **Move parent to a tracking role** — it becomes the "epic" or summary issue
39
+
40
+ **Split pattern:**
41
+
42
+ ```
43
+ Original: FLY-100 "Build auth system" (XL)
44
+ → FLY-101 "Add login endpoint" (S)
45
+ → FLY-102 "Add session management" (M)
46
+ → FLY-103 "Add role-based access control" (M)
47
+ → FLY-104 "Add password reset flow" (S)
48
+ ```
49
+
50
+ Don't force decomposition on every large issue — some are genuinely large and atomic. Use judgment. The prompt is: "This is estimated as XL. Can it be broken into smaller, independently deliverable pieces?"
@@ -52,6 +52,7 @@ When a conversation begins or the user returns after a gap:
52
52
 
53
53
  7. **Surface other product issues briefly** — If there are issues in the product scope
54
54
  but outside the active project, mention the count with a one-line summary:
55
+
55
56
  ```
56
57
  Also in [Product Name]: [N] issues across other projects (use --all to see)
57
58
  ```
@@ -69,10 +70,16 @@ automatically via the config cascade.
69
70
  When the user indicates they're done for the session:
70
71
 
71
72
  1. **Gather session data** — What was completed, what's in progress, what's blocked.
72
- 2. **Compose summary** using the template below.
73
- 3. **Determine health status** See health table.
74
- 4. **Post project update** `project_update.py` with health and summary body.
75
- 5. **Record session in context graph** Call `graph_session.py` with summary and issues worked on:
73
+ 2. **Knowledge capture check** Review the session's work for uncaptured knowledge:
74
+ - Were any architectural decisions made?
75
+ - Were any non-obvious behaviors or workarounds discovered?
76
+ - Were any patterns established that future work should follow?
77
+ - Did debugging reveal something worth documenting?
78
+ If yes, prompt the user: "This session involved [specific discovery]. Should we capture it in a knowledge doc before wrapping?" Use `/knowledge` if they agree.
79
+ 3. **Compose summary** using the template below.
80
+ 4. **Determine health status** — See health table.
81
+ 5. **Post project update** — `project_update.py` with health and summary body.
82
+ 6. **Record session in context graph** — Call `graph_session.py` with summary and issues worked on:
76
83
  ```
77
84
  python3 .claude/skills/flydocs-context-graph/scripts/graph_session.py \
78
85
  --summary "Brief summary of session outcomes" \
@@ -80,8 +87,8 @@ When the user indicates they're done for the session:
80
87
  [--decision NNN]
81
88
  ```
82
89
  This creates a session node for cross-session continuity. Skip silently if the script is not installed.
83
- 6. **Verify** — Confirm the project update was posted (update ID returned).
84
- 7. **Ask about uncommitted changes** — If git shows uncommitted work, offer to commit.
90
+ 7. **Verify** — Confirm the project update was posted (update ID returned).
91
+ 8. **Ask about uncommitted changes** — If git shows uncommitted work, offer to commit.
85
92
 
86
93
  Do not just summarize in chat. Actually post the update. Do not skip if the user seems in a hurry.
87
94
 
@@ -104,15 +111,16 @@ Do not just summarize in chat. Actually post the update. Do not skip if the user
104
111
 
105
112
  ### Health Status
106
113
 
107
- | Status | When to Use |
108
- |--------|-------------|
109
- | onTrack | Progress made, no blockers |
110
- | atRisk | Minor delays, attention needed |
114
+ | Status | When to Use |
115
+ | -------- | ------------------------------- |
116
+ | onTrack | Progress made, no blockers |
117
+ | atRisk | Minor delays, attention needed |
111
118
  | offTrack | Major blockers, behind schedule |
112
119
 
113
120
  ### Wrap Detection Phrases
114
121
 
115
122
  Offer session wrap when the user says:
123
+
116
124
  - "I'm done for today" / "wrapping up" / "that's it for now"
117
125
  - "save progress" / "end of day" / "stopping here"
118
126
 
@@ -120,9 +128,9 @@ Offer session wrap when the user says:
120
128
 
121
129
  Proactively surface issues that may be stuck:
122
130
 
123
- | State | Threshold | Action |
124
- |-------|-----------|--------|
125
- | Implementing | > 7 days without activity | Warn |
126
- | Review | > 3 days without activity | Warn |
127
- | Testing/QA | > 3 days without activity | Warn |
128
- | Blocked | Any | Always surface |
131
+ | State | Threshold | Action |
132
+ | ------------ | ------------------------- | -------------- |
133
+ | Implementing | > 7 days without activity | Warn |
134
+ | Review | > 3 days without activity | Warn |
135
+ | Testing/QA | > 3 days without activity | Warn |
136
+ | Blocked | Any | Always surface |
@@ -21,9 +21,14 @@ When the user has enough context to describe the issue:
21
21
  - **Why** — User story or business value
22
22
  - **How** — Technical notes or approach (if known)
23
23
  - **Done when** — Acceptance criteria as checkboxes
24
- 4. **Create issue** — `create_issue.py` with title, type, description, priority, and estimate (if known).
25
- 5. **Add comment** Use the Capture template from `reference/comment-templates.md`.
26
- 6. **Verify** Confirm issue identifier returned.
24
+ 4. **Apply labels** — Include appropriate labels from config:
25
+ - **Category label**: Automatic from issue type (feature, bug, chore, idea) via `issueLabels.category` in config
26
+ - **Repo label**: If multi-repo workspace, apply the repo label from `issueLabels.repo` in config
27
+ - **Product labels**: Applied automatically by the mechanism scripts from `workspace.product.labelIds`
28
+ - **Ad-hoc labels**: Only if explicitly relevant (e.g., "accessibility", "performance")
29
+ 5. **Create issue** — `create_issue.py` with title, type, description, priority, estimate (if known), and labels.
30
+ 6. **Add comment** — Use the Capture template from `reference/comment-templates.md`.
31
+ 7. **Verify** — Confirm issue identifier returned.
27
32
 
28
33
  ### Quick Capture
29
34
 
@@ -11,12 +11,13 @@ Archive verified and completed work.
11
11
  ## Steps
12
12
 
13
13
  1. **Verify QE approval** — Check issue comments for a "QE Approved" comment. If not found, do not close — direct to Validate stage first.
14
- 2. **Determine terminal state:**
14
+ 2. **Final knowledge check** — If the issue involved significant implementation, verify `knowledge/INDEX.md` reflects any decisions or discoveries. This is informational — don't block close, but prompt the user if notable knowledge appears uncaptured.
15
+ 3. **Determine terminal state:**
15
16
  - **Done** — Work completed and verified (normal path)
16
17
  - **Archived** — Deferring to a later date (not cancelled, may return)
17
18
  - **Canceled** — Not pursuing (won't be done)
18
- 3. **Transition** — `transition.py` with the appropriate Close comment from `reference/comment-templates.md`.
19
- 4. **Verify** — Confirm terminal state reached.
19
+ 4. **Transition** — `transition.py` with the appropriate Close comment from `reference/comment-templates.md`.
20
+ 5. **Verify** — Confirm terminal state reached.
20
21
 
21
22
  ## Gates
22
23