project-init 0.3.0__py3-none-any.whl

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 (173) hide show
  1. project_init/__init__.py +4 -0
  2. project_init/__main__.py +662 -0
  3. project_init/mcps.py +57 -0
  4. project_init/scaffold.py +374 -0
  5. project_init/templates/base/AGENTS.md.tmpl +50 -0
  6. project_init/templates/base/CLAUDE.md.tmpl +16 -0
  7. project_init/templates/base/CONTRIBUTING.md.tmpl +55 -0
  8. project_init/templates/base/GEMINI.md.tmpl +16 -0
  9. project_init/templates/base/LICENSE.tmpl +231 -0
  10. project_init/templates/base/SECURITY.md.tmpl +26 -0
  11. project_init/templates/base/docs/explanation/index.md +9 -0
  12. project_init/templates/base/docs/how-to/index.md +7 -0
  13. project_init/templates/base/docs/index.md.tmpl +20 -0
  14. project_init/templates/base/docs/reference/index.md +13 -0
  15. project_init/templates/base/docs/tutorials/index.md +7 -0
  16. project_init/templates/base/dot_claude/agents/README.md +30 -0
  17. project_init/templates/base/dot_claude/config.yaml.tmpl +31 -0
  18. project_init/templates/base/dot_claude/docs/README.md +26 -0
  19. project_init/templates/base/dot_claude/docs/adr/adr-001-memory-stack.md.tmpl +22 -0
  20. project_init/templates/base/dot_claude/docs/adr/adr-002-mcp-choices.md.tmpl +32 -0
  21. project_init/templates/base/dot_claude/docs/adr/adr-template.md +29 -0
  22. project_init/templates/base/dot_claude/docs/development/conventions.md.tmpl +31 -0
  23. project_init/templates/base/dot_claude/docs/development/testing.md +25 -0
  24. project_init/templates/base/dot_claude/docs/guides/developer-onboarding.md +110 -0
  25. project_init/templates/base/dot_claude/docs/guides/issue-metadata.md +27 -0
  26. project_init/templates/base/dot_claude/docs/guides/secrets.md +50 -0
  27. project_init/templates/base/dot_claude/docs/guides/using-memory.md +36 -0
  28. project_init/templates/base/dot_claude/hooks/README.md +15 -0
  29. project_init/templates/base/dot_claude/hooks/agent_guard_adapter.py.tmpl +64 -0
  30. project_init/templates/base/dot_claude/hooks/dag_workflow.py +610 -0
  31. project_init/templates/base/dot_claude/memory/MEMORY.md.tmpl +11 -0
  32. project_init/templates/base/dot_claude/memory/README.md +51 -0
  33. project_init/templates/base/dot_claude/memory/SCHEMA.md +52 -0
  34. project_init/templates/base/dot_claude/memory/feedback_conventions.md +11 -0
  35. project_init/templates/base/dot_claude/memory/project_context.md.tmpl +11 -0
  36. project_init/templates/base/dot_claude/memory/user_role.md +7 -0
  37. project_init/templates/base/dot_claude/project-init.md.tmpl +174 -0
  38. project_init/templates/base/dot_claude/rules/go.md +14 -0
  39. project_init/templates/base/dot_claude/rules/hooks.md +30 -0
  40. project_init/templates/base/dot_claude/rules/node.md +17 -0
  41. project_init/templates/base/dot_claude/rules/python.md +25 -0
  42. project_init/templates/base/dot_claude/scripts/README.md +15 -0
  43. project_init/templates/base/dot_claude/scripts/create_issue.sh +577 -0
  44. project_init/templates/base/dot_claude/scripts/create_nojira_pr.sh +3 -0
  45. project_init/templates/base/dot_claude/scripts/finish_pr.sh +3 -0
  46. project_init/templates/base/dot_claude/scripts/install_hooks.sh +55 -0
  47. project_init/templates/base/dot_claude/scripts/monitor_pr.sh +270 -0
  48. project_init/templates/base/dot_claude/scripts/promote_review.sh +3 -0
  49. project_init/templates/base/dot_claude/scripts/push_branch.sh +5 -0
  50. project_init/templates/base/dot_claude/scripts/push_wiki.sh +34 -0
  51. project_init/templates/base/dot_claude/scripts/setup_github.sh +219 -0
  52. project_init/templates/base/dot_claude/scripts/start_issue.sh +134 -0
  53. project_init/templates/base/dot_claude/settings.json.tmpl +83 -0
  54. project_init/templates/base/dot_claude/skills/README.md +12 -0
  55. project_init/templates/base/dot_claude/skills/plan/SKILL.md.tmpl +40 -0
  56. project_init/templates/base/dot_claude/vault/README.md +21 -0
  57. project_init/templates/base/dot_claude/vault/decisions/README.md +22 -0
  58. project_init/templates/base/dot_claude/vault/design/README.md +3 -0
  59. project_init/templates/base/dot_claude/vault/knowledge/README.md +5 -0
  60. project_init/templates/base/dot_claude/vault/sessions/README.md +5 -0
  61. project_init/templates/base/dot_devcontainer/devcontainer.json.tmpl +17 -0
  62. project_init/templates/base/dot_devcontainer/post-create.sh.tmpl +31 -0
  63. project_init/templates/base/dot_env.example.tmpl +13 -0
  64. project_init/templates/base/dot_github/CODEOWNERS.tmpl +12 -0
  65. project_init/templates/base/dot_github/ISSUE_TEMPLATE/bug.yml +98 -0
  66. project_init/templates/base/dot_github/ISSUE_TEMPLATE/chore.yml +82 -0
  67. project_init/templates/base/dot_github/ISSUE_TEMPLATE/config.yml +5 -0
  68. project_init/templates/base/dot_github/ISSUE_TEMPLATE/docs.yml +84 -0
  69. project_init/templates/base/dot_github/ISSUE_TEMPLATE/feature.yml +87 -0
  70. project_init/templates/base/dot_github/ISSUE_TEMPLATE/test.yml +90 -0
  71. project_init/templates/base/dot_github/copilot-instructions.md.tmpl +25 -0
  72. project_init/templates/base/dot_github/hooks/commit-msg +52 -0
  73. project_init/templates/base/dot_github/hooks/pre-commit +16 -0
  74. project_init/templates/base/dot_github/hooks/pre-push +51 -0
  75. project_init/templates/base/dot_github/pull_request_template.md +22 -0
  76. project_init/templates/base/dot_github/workflows/board-automation.yml +232 -0
  77. project_init/templates/base/dot_github/workflows/ci.yml.tmpl +204 -0
  78. project_init/templates/base/dot_github/workflows/docs.yml.tmpl +98 -0
  79. project_init/templates/base/dot_github/workflows/issue-validation.yml +72 -0
  80. project_init/templates/base/dot_github/workflows/review-status.yml +48 -0
  81. project_init/templates/base/dot_github/workflows/validate-pr.yml +103 -0
  82. project_init/templates/base/dot_gitignore.tmpl +41 -0
  83. project_init/templates/base/dot_golangci.yml.tmpl +20 -0
  84. project_init/templates/base/dot_vscode/extensions.json.tmpl +10 -0
  85. project_init/templates/base/dot_vscode/settings.json.tmpl +8 -0
  86. project_init/templates/base/eslint.config.mjs.tmpl +29 -0
  87. project_init/templates/base/justfile.tmpl +95 -0
  88. project_init/templates/base/mise.toml.tmpl +20 -0
  89. project_init/templates/base/mkdocs.yml.tmpl +32 -0
  90. project_init/templates/base/renovate.json +14 -0
  91. project_init/templates/base/ruff.toml.tmpl +31 -0
  92. project_init/templates/base/typedoc.json.tmpl +14 -0
  93. project_init/templates/codex/dot_agents/skills/add_adr/SKILL.md +33 -0
  94. project_init/templates/codex/dot_agents/skills/add_command/SKILL.md +63 -0
  95. project_init/templates/codex/dot_agents/skills/add_hook/SKILL.md +112 -0
  96. project_init/templates/codex/dot_agents/skills/audit/SKILL.md +146 -0
  97. project_init/templates/codex/dot_agents/skills/create_issue/SKILL.md +59 -0
  98. project_init/templates/codex/dot_agents/skills/github_workflow/SKILL.md +80 -0
  99. project_init/templates/codex/dot_agents/skills/request_review/SKILL.md +19 -0
  100. project_init/templates/codex/dot_agents/skills/review/SKILL.md +17 -0
  101. project_init/templates/codex/dot_agents/skills/save_memory/SKILL.md +17 -0
  102. project_init/templates/codex/dot_agents/skills/session_summary/SKILL.md +35 -0
  103. project_init/templates/codex/dot_agents/skills/start_task/SKILL.md +48 -0
  104. project_init/templates/codex/dot_agents/skills/status/SKILL.md +15 -0
  105. project_init/templates/codex/dot_codex/hooks.json.tmpl +17 -0
  106. project_init/templates/fallback/dot_claude/hooks/github_command_guard.sh +11 -0
  107. project_init/templates/fallback/dot_claude/hooks/post_edit_lint.sh +58 -0
  108. project_init/templates/fallback/dot_claude/hooks/pre_commit_gate.sh +81 -0
  109. project_init/templates/fallback/dot_claude/hooks/prod_guard.py +140 -0
  110. project_init/templates/fallback/dot_claude/hooks/session_setup.sh +62 -0
  111. project_init/templates/fallback/dot_claude/hooks/workflow_state_reminder.sh +72 -0
  112. project_init/templates/fallback/dot_claude/skills/INDEX.md +28 -0
  113. project_init/templates/fallback/dot_claude/skills/add_adr/SKILL.md +33 -0
  114. project_init/templates/fallback/dot_claude/skills/add_command/SKILL.md +63 -0
  115. project_init/templates/fallback/dot_claude/skills/add_hook/SKILL.md +112 -0
  116. project_init/templates/fallback/dot_claude/skills/audit/SKILL.md +146 -0
  117. project_init/templates/fallback/dot_claude/skills/create_issue/SKILL.md +59 -0
  118. project_init/templates/fallback/dot_claude/skills/github_workflow/SKILL.md +80 -0
  119. project_init/templates/fallback/dot_claude/skills/request_review/SKILL.md +19 -0
  120. project_init/templates/fallback/dot_claude/skills/review/SKILL.md +17 -0
  121. project_init/templates/fallback/dot_claude/skills/save_memory/SKILL.md +17 -0
  122. project_init/templates/fallback/dot_claude/skills/session_summary/SKILL.md +35 -0
  123. project_init/templates/fallback/dot_claude/skills/start_task/SKILL.md +48 -0
  124. project_init/templates/fallback/dot_claude/skills/status/SKILL.md +15 -0
  125. project_init/templates/gemini/dot_agents/skills/add_adr/SKILL.md +33 -0
  126. project_init/templates/gemini/dot_agents/skills/add_command/SKILL.md +63 -0
  127. project_init/templates/gemini/dot_agents/skills/add_hook/SKILL.md +112 -0
  128. project_init/templates/gemini/dot_agents/skills/audit/SKILL.md +146 -0
  129. project_init/templates/gemini/dot_agents/skills/create_issue/SKILL.md +59 -0
  130. project_init/templates/gemini/dot_agents/skills/github_workflow/SKILL.md +80 -0
  131. project_init/templates/gemini/dot_agents/skills/request_review/SKILL.md +19 -0
  132. project_init/templates/gemini/dot_agents/skills/review/SKILL.md +17 -0
  133. project_init/templates/gemini/dot_agents/skills/save_memory/SKILL.md +17 -0
  134. project_init/templates/gemini/dot_agents/skills/session_summary/SKILL.md +35 -0
  135. project_init/templates/gemini/dot_agents/skills/start_task/SKILL.md +48 -0
  136. project_init/templates/gemini/dot_agents/skills/status/SKILL.md +15 -0
  137. project_init/templates/gemini/dot_claude/scripts/setup_gemini.sh.tmpl +16 -0
  138. project_init/templates/gemini/dot_gemini-extension/commands/add_adr.toml +5 -0
  139. project_init/templates/gemini/dot_gemini-extension/commands/add_command.toml +5 -0
  140. project_init/templates/gemini/dot_gemini-extension/commands/add_hook.toml +5 -0
  141. project_init/templates/gemini/dot_gemini-extension/commands/audit.toml +5 -0
  142. project_init/templates/gemini/dot_gemini-extension/commands/create_issue.toml +5 -0
  143. project_init/templates/gemini/dot_gemini-extension/commands/github_workflow.toml +5 -0
  144. project_init/templates/gemini/dot_gemini-extension/commands/request_review.toml +5 -0
  145. project_init/templates/gemini/dot_gemini-extension/commands/review.toml +5 -0
  146. project_init/templates/gemini/dot_gemini-extension/commands/save_memory.toml +5 -0
  147. project_init/templates/gemini/dot_gemini-extension/commands/session_summary.toml +5 -0
  148. project_init/templates/gemini/dot_gemini-extension/commands/start_task.toml +5 -0
  149. project_init/templates/gemini/dot_gemini-extension/commands/status.toml +5 -0
  150. project_init/templates/gemini/dot_gemini-extension/gemini-extension.json.tmpl +6 -0
  151. project_init/templates/gemini/dot_gemini-extension/hooks/hooks.json.tmpl +18 -0
  152. project_init/templates/graphify/dot_claude/docs/guides/using-graphify.md +37 -0
  153. project_init/templates/graphify/dot_claude/rules/graphify.md +18 -0
  154. project_init/templates/graphify/dot_claude/scripts/setup_graphify.sh +40 -0
  155. project_init/templates/obsidian/dot_claude/scripts/lint_memory.sh +115 -0
  156. project_init/templates/obsidian/dot_claude/vault/decisions/adr-000-project-setup.md.tmpl +22 -0
  157. project_init/templates/obsidian/dot_claude/vault/dot_obsidian/README.md +31 -0
  158. project_init/templates/obsidian/dot_claude/vault/dot_obsidian/app.json +6 -0
  159. project_init/templates/obsidian/dot_claude/vault/dot_obsidian/community-plugins.json +1 -0
  160. project_init/templates/obsidian/dot_claude/vault/dot_obsidian/core-plugins.json +1 -0
  161. project_init/templates/obsidian/dot_claude/vault/log.md +6 -0
  162. project_init/templates/obsidian/dot_claude/vault/templates/decision.md +16 -0
  163. project_init/templates/obsidian/dot_claude/vault/templates/design-note.md +14 -0
  164. project_init/templates/obsidian/dot_claude/vault/templates/knowledge-note.md +12 -0
  165. project_init/templates/obsidian/dot_claude/vault/templates/session-note.md +16 -0
  166. project_init/templates/presets/obsidian-graphify.toml +16 -0
  167. project_init/templates/presets/obsidian-only.toml +14 -0
  168. project_init/upgrade.py +569 -0
  169. project_init-0.3.0.dist-info/METADATA +342 -0
  170. project_init-0.3.0.dist-info/RECORD +173 -0
  171. project_init-0.3.0.dist-info/WHEEL +4 -0
  172. project_init-0.3.0.dist-info/entry_points.txt +2 -0
  173. project_init-0.3.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,80 @@
1
+ ---
2
+ name: github_workflow
3
+ description: Guides the agent through the full GitHub PR lifecycle — branch naming, push, review responses, and merge. Loaded automatically before any push, PR creation, review response, or merge action.
4
+ when_to_use: Load before any push, PR creation, PR review response, merge, or release action — including when lifecycle scripts fail and a git/gh fallback is needed.
5
+ user-invocable: false
6
+ effort: high
7
+ allowed-tools: Bash(git *) Bash(gh *) Bash(.claude/scripts/*) Read
8
+ ---
9
+
10
+ Load this skill before any push, PR creation, review response, or merge action.
11
+
12
+ ## Quick reference
13
+
14
+ | Step | Pattern |
15
+ |------|---------|
16
+ | Branch | `<type>/<PROJECT-KEY>-<n>-<kebab-slug>` e.g. `feat/PI-42-add-oauth` |
17
+ | PR title | `type(PROJECT-123): description` e.g. `feat(PI-42): Add OAuth login` |
18
+ | No-issue PR | `type: description` (no scope) e.g. `fix: Fix typo` |
19
+ | PR body | Must include `Closes #N` (skip for no-issue PRs) |
20
+
21
+ Commit messages use the same format (Conventional Commits). Legacy `[PROJECT-123][type]` is accepted by validators during transition but must not be emitted.
22
+
23
+ Types: `feat` `fix` `chore` `docs` `test`
24
+
25
+ ## Standard lifecycle
26
+
27
+ 1. **Start work** — use the `start_task` skill. It runs `start_issue.sh` which creates
28
+ the branch, pushes, and opens a draft PR.
29
+ For minor no-issue work, use `.claude/scripts/create_nojira_pr.sh <type> "description"`.
30
+
31
+ 2. **Push during development:**
32
+ ```bash
33
+ .claude/scripts/push_branch.sh
34
+ ```
35
+ Never use bare `git push` — `push_branch.sh` retries transient GitHub errors.
36
+
37
+ 3. **Finish — push, mark ready, and merge:**
38
+ ```bash
39
+ .claude/scripts/finish_pr.sh [pr-number]
40
+ ```
41
+ `finish_pr.sh` pushes, marks the draft ready, runs `monitor_pr.sh --merge`,
42
+ and handles review cycles automatically.
43
+
44
+ Or run steps individually:
45
+ ```bash
46
+ .claude/scripts/push_branch.sh
47
+ .claude/scripts/promote_review.sh [pr-number]
48
+ .claude/scripts/monitor_pr.sh <pr-number> --merge
49
+ ```
50
+
51
+ ## Review cycle protocol
52
+
53
+ `monitor_pr.sh --merge` exits **1** for CI or merge failures and **2** when
54
+ `review/decision` fails while review cycles remain. Treat any non-zero exit as
55
+ unfinished work: inspect the printed failure, fix or retry, then rerun the
56
+ workflow. Do not report a PR as merged unless the script exits 0 after printing
57
+ the merged or auto-merge-enabled status.
58
+
59
+ 1. Post a response for each review comment:
60
+ ```
61
+ gh pr comment <pr-number> --body "**Review response:**
62
+ - [comment]: Fixing — <reason>
63
+ - [comment]: Not applying — <reason>"
64
+ ```
65
+ 2. Fix actionable code, then push: `.claude/scripts/push_branch.sh`
66
+ 3. Re-run with the next cycle number:
67
+ ```bash
68
+ .claude/scripts/monitor_pr.sh <pr-number> --merge --review-cycle <N>
69
+ ```
70
+ 4. After 1 review-fix cycle, the script auto force-merges with `--admin`.
71
+
72
+ **Before applying any comment:** read the current file state. Check whether the
73
+ comment is stale (already fixed), contradicts conventions, or is correct. Never
74
+ blindly apply a suggestion — post reasoning even when rejecting.
75
+
76
+ ## Issue titles vs PR titles
77
+
78
+ - **Issue titles**: plain description only — type is carried by the label.
79
+ - **PR titles**: must include `[type]` — PR titles become merge commit messages in `git log`.
80
+ - **nojira**: for minor fixes without a tracking issue; no `Closes #N` needed.
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: request_review
3
+ description: Mark the current draft PR ready for review
4
+ when_to_use: Use when a draft PR is ready to move from Draft to In Review status. Marks the PR ready and triggers board automation.
5
+ argument-hint: "[pr-number]"
6
+ allowed-tools: Bash Read
7
+ ---
8
+
9
+ Mark PR $ARGUMENTS (or current branch's PR if omitted) ready for review.
10
+
11
+ ## Steps
12
+
13
+ 1. **Promote to ready**:
14
+ ```bash
15
+ .claude/scripts/promote_review.sh $ARGUMENTS
16
+ ```
17
+ `board-automation.yml` moves the board card to **In Review** automatically.
18
+
19
+ 2. **Next steps**: Reviewers will be pinged. When they request changes, they'll post comments on the PR.
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: review
3
+ description: Review staged or recent changes for bugs, style issues, and missed edge cases
4
+ when_to_use: Use when you want a code review of work — staged changes, a specific commit, or a commit range.
5
+ argument-hint: "[commit-range or file]"
6
+ allowed-tools: Bash Read Grep Glob
7
+ ---
8
+
9
+ Review the code changes specified by: $ARGUMENTS
10
+
11
+ If no argument given, review all staged changes (`git diff --cached`). If nothing is staged, review the last commit.
12
+
13
+ Focus on:
14
+ - **Bugs** — logic errors, off-by-ones, null/undefined risks
15
+ - **Security** — injection, auth issues, secret exposure
16
+ - **Style** — naming, dead code, overly complex logic
17
+ - **Edge cases** — empty inputs, concurrency, error paths
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: save_memory
3
+ description: Save a fact to project memory for future sessions
4
+ when_to_use: Use when you learn something important that should persist across conversations — a decision, a constraint, a pattern, or an external reference.
5
+ argument-hint: "<fact to remember>"
6
+ allowed-tools: Read Write Glob
7
+ ---
8
+
9
+ Save this to project memory: $ARGUMENTS
10
+
11
+ Follow the memory convention in `.claude/memory/README.md`:
12
+
13
+ 1. Decide the memory type (user / feedback / project / reference)
14
+ 2. Choose a descriptive filename (e.g., `feedback_testing.md`, `project_deadline.md`)
15
+ 3. Check if an existing memory file already covers this — update it instead of duplicating
16
+ 4. Write the file with proper frontmatter (name, description, type)
17
+ 5. Add a one-line entry to `.claude/memory/MEMORY.md`
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: session_summary
3
+ description: Summarizes the current session and saves it to the vault. Use at the end of a work session to record completed work, decisions made, and open items for the next session.
4
+ when_to_use: Use when the user says "save the session", "wrap up", "summarize what we did", or at the end of a long work session.
5
+ effort: medium
6
+ allowed-tools: Bash(git *) Read Write Glob Grep
7
+ ---
8
+
9
+ Summarize this session and save it to the vault:
10
+
11
+ 1. **Gather context**:
12
+ - Run `git log --since='2 hours ago' --oneline` for recent commits
13
+ - Run `git diff --stat` for uncommitted changes
14
+ - Review the conversation for key decisions and discoveries
15
+
16
+ 2. **Write the summary** to `.claude/vault/sessions/` with today's date:
17
+ ```
18
+ # Session YYYY-MM-DD (manual)
19
+
20
+ ## What was done
21
+ - (bullet list of completed work)
22
+
23
+ ## Decisions made
24
+ - (any architectural or approach decisions, with reasoning)
25
+
26
+ ## Open items
27
+ - (anything left unfinished or discovered but not addressed)
28
+
29
+ ## Notes
30
+ - (anything else worth remembering)
31
+ ```
32
+
33
+ 3. **Update memory** if any reusable facts emerged (write to the project memory directory)
34
+
35
+ Keep the summary concise — a future agent should be able to skim it in 30 seconds.
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: start_task
3
+ description: Creates a GitHub Issue, branch, and draft PR before implementation begins. Use before any non-trivial task to keep work traceable — one issue, one branch, one PR.
4
+ when_to_use: Use when the user says "start work on X", "create a ticket for Y", or "begin a new task". Do not use for trivial one-off changes that don't need tracking.
5
+ argument-hint: "[task title]"
6
+ allowed-tools: Bash(gh *) Bash(git *) Read
7
+ ---
8
+
9
+ Before starting any non-trivial task, create a GitHub Issue, a dedicated branch, and a draft PR. This keeps work traceable and every PR maps to exactly one issue.
10
+
11
+ ## Mandatory scripts
12
+
13
+ | Action | Script | Never use |
14
+ |--------|--------|-----------|
15
+ | Start issue + branch + draft PR | `.claude/scripts/start_issue.sh <n> <type>` | bare `git checkout -b` + bare `gh pr create` |
16
+ | Push branch | `.claude/scripts/push_branch.sh` | bare `git push` |
17
+ | **Push + promote + merge (all-in-one)** | `.claude/scripts/finish_pr.sh <n>` | `gh pr ready`, bare `gh pr merge`, `gh pr checks --watch` |
18
+
19
+ ## Steps
20
+
21
+ 1. **Clarify scope** — if $ARGUMENTS is empty or vague, ask the user for:
22
+ - Task title (one line, imperative: "Add X", "Fix Y", "Refactor Z")
23
+ - Work type: `feat` / `fix` / `chore` / `docs` / `test`
24
+
25
+ 2. **Check for existing issue and PR** — run `gh issue list` and `gh pr list`. If an issue already exists, use its number. If a draft PR already exists for that issue, use it — do **not** create a second PR. Skip to step 5.
26
+
27
+ 3. **Create the issue** — load the `create_issue` skill and follow it. It gathers priority, area, size, references, dependencies, and acceptance criteria before running:
28
+ ```bash
29
+ ISSUE_NUMBER=$(.claude/scripts/create_issue.sh <type> "<title>" --priority <priority> --area "<area>" --size <size> --acceptance "<criterion>")
30
+ echo "Created issue #$ISSUE_NUMBER"
31
+ ```
32
+
33
+ 4. **Start work** — create the branch, push, and open a draft PR:
34
+ ```bash
35
+ .claude/scripts/start_issue.sh <issue-number> <type>
36
+ ```
37
+ This derives the branch name (`<issue_type>/<project_abbr>-<issue_number>-<slug>`) from the issue title, pushes it, and opens a draft PR with the correct `[PROJECT-123][type]` title and `Closes #n` body.
38
+
39
+ 5. **Proceed** — only begin implementation after the scripts have run successfully.
40
+
41
+ 6. **When ready to merge** — load the `github_workflow` skill for the
42
+ full push → promote → monitor/merge lifecycle and review-cycle protocol.
43
+
44
+ ## Rules
45
+
46
+ - Every non-trivial task must have a GitHub Issue, a branch, and a draft PR — all before the first line of implementation code.
47
+ - One issue → one branch → one PR.
48
+ - `board-automation.yml` moves the board card to **In Progress** automatically when the PR is opened. No manual board move needed.
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: status
3
+ description: Show project status — git state, recent commits, open tasks, and memory summary
4
+ when_to_use: Use when you want a quick snapshot of the project — current branch, uncommitted changes, recent work, active memory, and open TODOs.
5
+ allowed-tools: Bash Read Grep Glob
6
+ ---
7
+
8
+ Give me a concise project status report:
9
+
10
+ 1. **Git state** — current branch, uncommitted changes, commits ahead/behind remote
11
+ 2. **Recent work** — last 5 commits (one line each)
12
+ 3. **Memory** — read `.claude/memory/MEMORY.md` and list the key facts
13
+ 4. **Open items** — scan for TODO/FIXME/HACK in the codebase (top 10)
14
+
15
+ Keep the report under 30 lines. Use markdown formatting.
@@ -0,0 +1,17 @@
1
+ {{#if codex}}{
2
+ "hooks": {
3
+ "PreToolUse": [
4
+ {
5
+ "matcher": "Bash",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "python3 .claude/hooks/agent_guard_adapter.py codex",
10
+ "timeout": 10
11
+ }
12
+ ]
13
+ }
14
+ ]
15
+ }
16
+ }
17
+ {{/if codex}}
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env bash
2
+ # github_command_guard.sh — delegate to dag_workflow.py guard.
3
+ # PreToolUse hook on Bash. Receives tool input JSON on stdin.
4
+ #
5
+ # All command-pattern matching, redirect rules, and DAG prerequisite checks
6
+ # live in dag_workflow.py next to this script. Adding a new banned command
7
+ # means editing COMMAND_RULES there, not this file.
8
+
9
+ set -euo pipefail
10
+
11
+ exec python3 "$(dirname "$0")/dag_workflow.py" guard
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env bash
2
+ # post_edit_lint.sh — runs linter on edited files after Edit/Write/MultiEdit.
3
+ # Invoked by Claude Code's PostToolUse hook.
4
+ # Outputs additionalContext JSON if unfixable lint errors remain so Claude
5
+ # self-corrects in the same turn.
6
+
7
+ set -euo pipefail
8
+
9
+ ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
10
+ INPUT=$(cat)
11
+
12
+ FILE=$(printf '%s' "$INPUT" | python3 -c "
13
+ import json, sys
14
+ try:
15
+ d = json.load(sys.stdin)
16
+ except Exception:
17
+ sys.exit(0)
18
+ ti = d.get('tool_input', {}) or {}
19
+ print(ti.get('file_path') or ti.get('filePath') or '')
20
+ " 2>/dev/null || true)
21
+
22
+ [ -z "$FILE" ] && exit 0
23
+ [ ! -f "$FILE" ] && exit 0
24
+
25
+ ERRORS=""
26
+
27
+ case "$FILE" in
28
+ *.py)
29
+ # Prefer 'uv run ruff' inside a uv-managed project so the hook uses
30
+ # the same ruff the project itself uses; fall back to a system ruff.
31
+ if { [ -f "$ROOT/pyproject.toml" ] || [ -f "$ROOT/uv.lock" ]; } && command -v uv &>/dev/null; then
32
+ uv run ruff check --fix --quiet "$FILE" 2>/dev/null || true
33
+ uv run ruff format --quiet "$FILE" 2>/dev/null || true
34
+ ERRORS=$(uv run ruff check --quiet "$FILE" 2>&1 || true)
35
+ elif command -v ruff &>/dev/null; then
36
+ ruff check --fix --quiet "$FILE" 2>/dev/null || true
37
+ ruff format --quiet "$FILE" 2>/dev/null || true
38
+ ERRORS=$(ruff check --quiet "$FILE" 2>&1 || true)
39
+ fi
40
+ ;;
41
+ *.js|*.ts|*.jsx|*.tsx)
42
+ # Use bunx (bun's package runner) — consistent with project convention (PI-15).
43
+ if command -v bunx &>/dev/null; then
44
+ bunx eslint --fix --quiet "$FILE" 2>/dev/null || true
45
+ ERRORS=$(bunx eslint --quiet "$FILE" 2>&1 || true)
46
+ fi
47
+ ;;
48
+ esac
49
+
50
+ if [ -n "$ERRORS" ]; then
51
+ python3 -c "
52
+ import json, sys
53
+ file, errors = sys.argv[1], sys.argv[2]
54
+ print(json.dumps({'additionalContext': f'Lint errors in {file} (after auto-fix attempt) — please fix before continuing:\n{errors}'}))
55
+ " "$FILE" "$ERRORS"
56
+ fi
57
+
58
+ exit 0
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env bash
2
+ # pre_commit_gate.sh — blocks git commit if staged files fail linting.
3
+ # PreToolUse hook on Bash. Receives tool input JSON on stdin.
4
+ # Auto-fixes what it can and re-stages; blocks only if errors remain.
5
+
6
+ set -euo pipefail
7
+
8
+ INPUT=$(cat)
9
+
10
+ CMD=$(printf '%s' "$INPUT" | python3 -c "
11
+ import json, sys
12
+ try:
13
+ d = json.load(sys.stdin)
14
+ except Exception:
15
+ sys.exit(0)
16
+ print((d.get('tool_input', {}) or {}).get('command', '') or '')
17
+ " 2>/dev/null || true)
18
+
19
+ # Only intercept git commit commands
20
+ case "$CMD" in
21
+ *"git commit"*) ;;
22
+ *) exit 0 ;;
23
+ esac
24
+
25
+ ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
26
+ ERRORS=""
27
+
28
+ # Lint and auto-fix staged Python files. Prefer 'uv run ruff' inside a
29
+ # uv-managed project so the hook uses the same ruff the project itself uses;
30
+ # fall back to a system ruff binary.
31
+ mapfile -t STAGED_PY < <(git diff --cached --name-only --diff-filter=ACM 2>/dev/null | grep '\.py$' || true)
32
+ if [ "${#STAGED_PY[@]}" -gt 0 ]; then
33
+ LINT_OUT=""
34
+ if { [ -f "$ROOT/pyproject.toml" ] || [ -f "$ROOT/uv.lock" ]; } && command -v uv &>/dev/null; then
35
+ uv run ruff check --fix --quiet "${STAGED_PY[@]}" 2>/dev/null || true
36
+ uv run ruff format --quiet "${STAGED_PY[@]}" 2>/dev/null || true
37
+ LINT_OUT=$(uv run ruff check --quiet "${STAGED_PY[@]}" 2>&1 || true)
38
+ elif command -v ruff &>/dev/null; then
39
+ ruff check --fix --quiet "${STAGED_PY[@]}" 2>/dev/null || true
40
+ ruff format --quiet "${STAGED_PY[@]}" 2>/dev/null || true
41
+ LINT_OUT=$(ruff check --quiet "${STAGED_PY[@]}" 2>&1 || true)
42
+ fi
43
+ if [ -n "$LINT_OUT" ]; then
44
+ ERRORS="${ERRORS}Python lint errors:\n${LINT_OUT}\n"
45
+ fi
46
+ # Re-stage auto-fixed files so the commit includes the fixes
47
+ git add "${STAGED_PY[@]}" 2>/dev/null || true
48
+ fi
49
+
50
+ # Lint and auto-fix staged JS/TS files
51
+ # Use bunx (bun's package runner) — consistent with project convention (PI-15).
52
+ mapfile -t STAGED_JS < <(git diff --cached --name-only --diff-filter=ACM 2>/dev/null | grep -E '\.(js|ts|jsx|tsx)$' || true)
53
+ if [ "${#STAGED_JS[@]}" -gt 0 ] && command -v bunx &>/dev/null; then
54
+ bunx eslint --fix --quiet "${STAGED_JS[@]}" 2>/dev/null || true
55
+ LINT_OUT=$(bunx eslint --quiet "${STAGED_JS[@]}" 2>&1 || true)
56
+ if [ -n "$LINT_OUT" ]; then
57
+ ERRORS="${ERRORS}JS/TS lint errors:\n${LINT_OUT}\n"
58
+ fi
59
+ git add "${STAGED_JS[@]}" 2>/dev/null || true
60
+ fi
61
+
62
+ # PI-139: when the project ships a justfile with a lint recipe and just is
63
+ # installed, additionally gate on `just lint` — the same definition of "lint
64
+ # passes" CI and every agent use. Per-file findings above are preserved: the
65
+ # recipe is language-specific, so in a mixed repo it may not cover everything
66
+ # the per-file checks caught (a passing recipe must not wash those out).
67
+ if command -v just >/dev/null 2>&1 && [ -f "$ROOT/justfile" ] \
68
+ && (cd "$ROOT" && just --show lint >/dev/null 2>&1); then
69
+ JUST_OUT=$(cd "$ROOT" && just lint 2>&1) || ERRORS="${ERRORS}Lint errors (just lint):\n${JUST_OUT}\n"
70
+ fi
71
+
72
+ if [ -n "$ERRORS" ]; then
73
+ python3 -c "
74
+ import json, sys
75
+ errors = sys.argv[1].replace('\\\\n', '\n')
76
+ msg = 'Pre-commit lint check failed. Fix these errors before committing:\n\n' + errors
77
+ print(json.dumps({'decision': 'block', 'reason': msg}))
78
+ " "$ERRORS"
79
+ fi
80
+
81
+ exit 0
@@ -0,0 +1,140 @@
1
+ """Prod-safety guard (PI-168, ADR-012): deny destructive infra/DB commands.
2
+
3
+ PreToolUse hook on Bash. Deterministic deny-table — no LLM, no network.
4
+ Destructive operations that bypass the git/CI boundary (cloud deletes,
5
+ DROP DATABASE, terraform destroy, …) get:
6
+
7
+ - ``ask`` in interactive sessions — a human confirms or rejects;
8
+ - ``block`` in fully autonomous sessions (``bypassPermissions``) — there is
9
+ no human to ask, so the command is blocked outright.
10
+
11
+ Escape hatch: ``safety.allow`` in ``.claude/config.yaml`` holds a JSON list
12
+ of regex patterns; a command matching any of them is never flagged. Use it
13
+ for known-safe contexts (e.g. a dev-cluster kubectl context).
14
+
15
+ This is a guardrail, not the security boundary (ADR-007/ADR-012): a
16
+ sufficiently creative command can evade a deny-list. The guarantee comes
17
+ from credential separation — agent sessions must never hold production
18
+ credentials (see .claude/docs/guides/secrets.md).
19
+
20
+ Fail-open by design: any internal error lets the command proceed.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import json
26
+ import re
27
+ import sys
28
+ from pathlib import Path
29
+
30
+ # (pattern, label) — matched against the full command string. ``_SEG``
31
+ # tolerates global flags between the CLI name and the destructive verb
32
+ # (e.g. `kubectl --context prod delete …`) while stopping at pipeline and
33
+ # command separators; the cost is rare false positives on odd resource
34
+ # names, which the ask/allowlist paths absorb cheaply.
35
+ _SEG = r"[^|;&]*?"
36
+ DENY_RULES: list[tuple[re.Pattern[str], str]] = [
37
+ (re.compile(r"\bterraform\s+(destroy|apply\s+.*-destroy)\b"), "terraform destroy"),
38
+ (re.compile(rf"\bkubectl\b{_SEG}\bdelete\b"), "kubectl delete"),
39
+ (re.compile(rf"\bhelm\b{_SEG}\b(uninstall|delete)\b"), "helm uninstall"),
40
+ (re.compile(rf"\baws\b{_SEG}\b(delete|terminate|remove)\S*\b"), "aws delete/terminate"),
41
+ (re.compile(rf"\baws\b{_SEG}\bs3\s+(rb\b|rm\b{_SEG}--recursive)"), "aws s3 bucket/recursive removal"),
42
+ (re.compile(rf"\bgcloud\b{_SEG}\bdelete\b"), "gcloud delete"),
43
+ (re.compile(rf"\baz\b{_SEG}\bdelete\b"), "az delete"),
44
+ (re.compile(r"\bdrop\s+(table|database|schema)\b", re.IGNORECASE), "SQL DROP"),
45
+ (re.compile(r"\btruncate\s+table\b", re.IGNORECASE), "SQL TRUNCATE"),
46
+ (re.compile(r"\brm\s+(-[a-zA-Z]*r[a-zA-Z]*f|-[a-zA-Z]*f[a-zA-Z]*r)[a-zA-Z]*\s+(/(?!tmp\b)|~)"),
47
+ "recursive force-remove outside the project"),
48
+ (re.compile(r"\bgh\s+repo\s+delete\b"), "gh repo delete"),
49
+ (re.compile(r"\bdocker\s+(volume\s+prune|system\s+prune)\b"), "docker prune"),
50
+ ]
51
+
52
+ # Fully autonomous mode: no human is watching the prompt, so "ask" is
53
+ # meaningless — block outright. Other modes (default, plan, acceptEdits)
54
+ # still surface an interactive permission prompt for Bash.
55
+ _AUTONOMOUS_MODES = {"bypassPermissions", "dangerouslySkipPermissions"}
56
+
57
+
58
+ def _find_config(start: Path) -> Path | None:
59
+ """Walk up from *start* to the project's .claude/config.yaml, if any."""
60
+ for candidate in (start, *start.parents):
61
+ config = candidate / ".claude" / "config.yaml"
62
+ if config.is_file():
63
+ return config
64
+ return None
65
+
66
+
67
+ def _allow_patterns(root: Path) -> list[re.Pattern[str]]:
68
+ """Read the safety.allow JSON list from .claude/config.yaml (fail-open).
69
+
70
+ *root* is the Bash tool's cwd, which may be a subdirectory after `cd` —
71
+ the config is located by walking up the tree.
72
+ """
73
+ config = _find_config(root)
74
+ if config is None:
75
+ return []
76
+ try:
77
+ in_safety = False
78
+ for line in config.read_text(encoding="utf-8").splitlines():
79
+ if line.startswith("safety:"):
80
+ in_safety = True
81
+ continue
82
+ if in_safety:
83
+ if line.strip() and not line.startswith(" "):
84
+ break
85
+ stripped = line.strip()
86
+ if stripped.startswith("allow:"):
87
+ raw = stripped.split(":", 1)[1].strip()
88
+ return [re.compile(p) for p in json.loads(raw)]
89
+ except (OSError, json.JSONDecodeError, re.error):
90
+ pass
91
+ return []
92
+
93
+
94
+ def evaluate(command: str, permission_mode: str, allow: list[re.Pattern[str]]) -> dict | None:
95
+ """Return the hook verdict for *command*, or None to let it through."""
96
+ if any(p.search(command) for p in allow):
97
+ return None
98
+ for pattern, label in DENY_RULES:
99
+ if pattern.search(command):
100
+ reason = (
101
+ f"prod_guard: '{label}' is a destructive operation. "
102
+ "If this is intentional and safe, add a matching regex to "
103
+ "safety.allow in .claude/config.yaml, or run it yourself. "
104
+ "(Guardrail only — real protection is credential separation, "
105
+ "see .claude/docs/guides/secrets.md.)"
106
+ )
107
+ if permission_mode in _AUTONOMOUS_MODES:
108
+ return {"decision": "block", "reason": reason}
109
+ return {
110
+ "hookSpecificOutput": {
111
+ "hookEventName": "PreToolUse",
112
+ "permissionDecision": "ask",
113
+ "permissionDecisionReason": reason,
114
+ }
115
+ }
116
+ return None
117
+
118
+
119
+ def main() -> int:
120
+ """Read the PreToolUse payload from stdin; print a verdict if any."""
121
+ try:
122
+ payload = json.loads(sys.stdin.read() or "{}")
123
+ except json.JSONDecodeError:
124
+ return 0
125
+ command = ((payload.get("tool_input") or {}).get("command") or "").strip()
126
+ if not command:
127
+ return 0
128
+ mode = payload.get("permission_mode") or payload.get("permissionMode") or ""
129
+ root = Path(payload.get("cwd") or ".")
130
+ try:
131
+ verdict = evaluate(command, mode, _allow_patterns(root))
132
+ except Exception: # noqa: BLE001 — guardrail must never break the session
133
+ return 0
134
+ if verdict is not None:
135
+ sys.stdout.write(json.dumps(verdict))
136
+ return 0
137
+
138
+
139
+ if __name__ == "__main__":
140
+ sys.exit(main())
@@ -0,0 +1,62 @@
1
+ #!/bin/bash
2
+ # SessionStart bootstrap (PI-146): make a fresh/remote container immediately
3
+ # usable — sync dependencies so tests and linters run instead of failing on
4
+ # a missing venv. Fast on warm environments: a content stamp of the
5
+ # dependency manifests short-circuits before any tool runs.
6
+ set -uo pipefail # not -e: a failed bootstrap must never break the session
7
+
8
+ ROOT="${CLAUDE_PROJECT_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
9
+ cd "$ROOT" || exit 0
10
+ STAMP=".claude/.session_setup_stamp"
11
+ LOG=".claude/logs/session_setup.log"
12
+ mkdir -p .claude/logs
13
+
14
+ fingerprint() {
15
+ cat pyproject.toml uv.lock package.json bun.lock bun.lockb go.mod go.sum 2>/dev/null \
16
+ | sha256sum | cut -d' ' -f1
17
+ }
18
+
19
+ # The stamp alone is not enough: an ephemeral container can restore the repo
20
+ # (stamp included) without the synced environment, so check for it too.
21
+ env_present() {
22
+ { [ ! -f pyproject.toml ] || [ -d .venv ]; } \
23
+ && { [ ! -f package.json ] || [ -d node_modules ]; }
24
+ }
25
+
26
+ CURRENT="$(fingerprint)"
27
+ if [ -f "$STAMP" ] && [ "$(cat "$STAMP" 2>/dev/null)" = "$CURRENT" ] && env_present; then
28
+ exit 0 # warm environment — nothing to do
29
+ fi
30
+
31
+ bootstrap() {
32
+ # Prefer the justfile setup recipe — the canonical bootstrap entry point.
33
+ if command -v just >/dev/null 2>&1 && [ -f justfile ] \
34
+ && just --show setup >/dev/null 2>&1; then
35
+ just setup
36
+ elif [ -f pyproject.toml ] && command -v uv >/dev/null 2>&1; then
37
+ uv sync --extra dev 2>/dev/null || uv sync
38
+ elif [ -f package.json ] && command -v bun >/dev/null 2>&1; then
39
+ bun install
40
+ elif [ -f go.mod ] && command -v go >/dev/null 2>&1; then
41
+ go mod download
42
+ else
43
+ return 2 # nothing recognized to set up
44
+ fi
45
+ }
46
+
47
+ bootstrap >"$LOG" 2>&1
48
+ case $? in
49
+ 0)
50
+ echo "$CURRENT" >"$STAMP"
51
+ echo "session_setup: dependencies synced for fresh environment"
52
+ ;;
53
+ 2)
54
+ # No manifest/tool to bootstrap: stamp silently so later sessions skip
55
+ # the probe, but claim nothing — no sync happened.
56
+ echo "$CURRENT" >"$STAMP"
57
+ ;;
58
+ *)
59
+ echo "session_setup: bootstrap failed — see $LOG" >&2
60
+ ;;
61
+ esac
62
+ exit 0