vyuha 0.1.0__tar.gz

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 (89) hide show
  1. vyuha-0.1.0/.claude/commands/implement.md +81 -0
  2. vyuha-0.1.0/.claude/commands/integrate.md +23 -0
  3. vyuha-0.1.0/.claude/commands/next-ticket.md +7 -0
  4. vyuha-0.1.0/.claude/commands/orchestrate.md +392 -0
  5. vyuha-0.1.0/.claude/commands/tickets.md +7 -0
  6. vyuha-0.1.0/.github/workflows/ci.yml +63 -0
  7. vyuha-0.1.0/.gitignore +30 -0
  8. vyuha-0.1.0/.vyuha/notes/.gitkeep +0 -0
  9. vyuha-0.1.0/.vyuha.yml.example +65 -0
  10. vyuha-0.1.0/LICENSE +202 -0
  11. vyuha-0.1.0/NOTICE +14 -0
  12. vyuha-0.1.0/PKG-INFO +633 -0
  13. vyuha-0.1.0/README.md +385 -0
  14. vyuha-0.1.0/ROADMAP.md +41 -0
  15. vyuha-0.1.0/SECURITY.md +34 -0
  16. vyuha-0.1.0/ci/run_pytest.py +105 -0
  17. vyuha-0.1.0/ci/smoke_windows.py +156 -0
  18. vyuha-0.1.0/docs/ARCHITECTURE.md +202 -0
  19. vyuha-0.1.0/docs/assets/demo.gif +0 -0
  20. vyuha-0.1.0/docs/config-reference.md +213 -0
  21. vyuha-0.1.0/docs/demo-walkthrough.md +245 -0
  22. vyuha-0.1.0/docs/executor-capabilities.md +123 -0
  23. vyuha-0.1.0/docs/security-model.md +156 -0
  24. vyuha-0.1.0/docs/troubleshooting.md +281 -0
  25. vyuha-0.1.0/pyproject.toml +88 -0
  26. vyuha-0.1.0/tests/__init__.py +0 -0
  27. vyuha-0.1.0/tests/test_analyze.py +1024 -0
  28. vyuha-0.1.0/tests/test_board.py +380 -0
  29. vyuha-0.1.0/tests/test_claim_file.py +158 -0
  30. vyuha-0.1.0/tests/test_cli.py +353 -0
  31. vyuha-0.1.0/tests/test_concurrency.py +315 -0
  32. vyuha-0.1.0/tests/test_config.py +921 -0
  33. vyuha-0.1.0/tests/test_context_log.py +1342 -0
  34. vyuha-0.1.0/tests/test_create.py +308 -0
  35. vyuha-0.1.0/tests/test_deploy.py +202 -0
  36. vyuha-0.1.0/tests/test_doctor.py +303 -0
  37. vyuha-0.1.0/tests/test_flags.py +217 -0
  38. vyuha-0.1.0/tests/test_lifecycle.py +1839 -0
  39. vyuha-0.1.0/tests/test_orchestrate.py +3539 -0
  40. vyuha-0.1.0/tests/test_pidutil.py +43 -0
  41. vyuha-0.1.0/tests/test_projects.py +326 -0
  42. vyuha-0.1.0/tests/test_promote.py +134 -0
  43. vyuha-0.1.0/tests/test_prompts.py +503 -0
  44. vyuha-0.1.0/tests/test_reviewer.py +444 -0
  45. vyuha-0.1.0/tests/test_safeguards.py +582 -0
  46. vyuha-0.1.0/tests/test_ticket.py +411 -0
  47. vyuha-0.1.0/tests/test_watch.py +371 -0
  48. vyuha-0.1.0/tests/test_worktree.py +59 -0
  49. vyuha-0.1.0/vyuha/__init__.py +4 -0
  50. vyuha-0.1.0/vyuha/analyze.py +842 -0
  51. vyuha-0.1.0/vyuha/board.py +637 -0
  52. vyuha-0.1.0/vyuha/claim_file.py +96 -0
  53. vyuha-0.1.0/vyuha/cli.py +1035 -0
  54. vyuha-0.1.0/vyuha/companion.py +74 -0
  55. vyuha-0.1.0/vyuha/concurrency.py +224 -0
  56. vyuha-0.1.0/vyuha/config.py +768 -0
  57. vyuha-0.1.0/vyuha/context_log.py +917 -0
  58. vyuha-0.1.0/vyuha/create.py +150 -0
  59. vyuha-0.1.0/vyuha/deploy.py +130 -0
  60. vyuha-0.1.0/vyuha/doctor.py +190 -0
  61. vyuha-0.1.0/vyuha/executor.py +146 -0
  62. vyuha-0.1.0/vyuha/flags.py +131 -0
  63. vyuha-0.1.0/vyuha/ghsync.py +121 -0
  64. vyuha-0.1.0/vyuha/lifecycle.py +1207 -0
  65. vyuha-0.1.0/vyuha/mcp.py +369 -0
  66. vyuha-0.1.0/vyuha/orchestrate.py +1890 -0
  67. vyuha-0.1.0/vyuha/pidutil.py +84 -0
  68. vyuha-0.1.0/vyuha/projects.py +81 -0
  69. vyuha-0.1.0/vyuha/promote.py +160 -0
  70. vyuha-0.1.0/vyuha/prompts.py +117 -0
  71. vyuha-0.1.0/vyuha/reviewer.py +188 -0
  72. vyuha-0.1.0/vyuha/safeguards.py +162 -0
  73. vyuha-0.1.0/vyuha/skills/implement.md +81 -0
  74. vyuha-0.1.0/vyuha/skills/integrate.md +23 -0
  75. vyuha-0.1.0/vyuha/skills/next-ticket.md +7 -0
  76. vyuha-0.1.0/vyuha/skills/orchestrate.md +401 -0
  77. vyuha-0.1.0/vyuha/skills/tickets.md +7 -0
  78. vyuha-0.1.0/vyuha/stats.py +123 -0
  79. vyuha-0.1.0/vyuha/templates/__init__.py +0 -0
  80. vyuha-0.1.0/vyuha/templates/prompts/__init__.py +0 -0
  81. vyuha-0.1.0/vyuha/templates/prompts/analyze.md +29 -0
  82. vyuha-0.1.0/vyuha/templates/prompts/implement.md +1 -0
  83. vyuha-0.1.0/vyuha/templates/prompts/review.md +1 -0
  84. vyuha-0.1.0/vyuha/templates/scripts/__init__.py +0 -0
  85. vyuha-0.1.0/vyuha/templates/scripts/pre-deploy-check.sh +16 -0
  86. vyuha-0.1.0/vyuha/templates/scripts/run-tests.sh +14 -0
  87. vyuha-0.1.0/vyuha/ticket.py +229 -0
  88. vyuha-0.1.0/vyuha/watch.py +219 -0
  89. vyuha-0.1.0/vyuha/worktree.py +104 -0
@@ -0,0 +1,81 @@
1
+ # /implement — Start a Ticket
2
+
3
+ Claims a ticket and creates its git worktree.
4
+
5
+ **Usage:** `/implement TICK-NNN`
6
+
7
+ ```bash
8
+ vyuha start $ARGUMENTS
9
+ ```
10
+
11
+ After the worktree is created (`worktrees/<ticket-id>/`), edit files **there** — never edit the main checkout's copies. Reset CWD between tickets.
12
+
13
+ Run tests from within the worktree (use relative paths to your test runner). When tests are green:
14
+
15
+ ```bash
16
+ vyuha complete $ARGUMENTS
17
+ ```
18
+
19
+ Then merge:
20
+
21
+ ```bash
22
+ vyuha merge $ARGUMENTS
23
+ ```
24
+
25
+ ---
26
+
27
+ ## Writing agent notes
28
+
29
+ After completing a ticket (tests green, `vyuha complete` called), write a short notes block for each file in `ticket.touches` so future agents inherit constraints discovered during this implementation.
30
+
31
+ ### Note file location
32
+
33
+ For each file path in `ticket.touches`, the note file is:
34
+
35
+ ```
36
+ .vyuha/notes/<flat_path>.md
37
+ ```
38
+
39
+ where `<flat_path>` is the file path with every `/` replaced by `_`.
40
+
41
+ Examples:
42
+ - `src/vyuha/core.py` → `.vyuha/notes/src_vyuha_core.py.md`
43
+ - `.claude/commands/implement.md` → `.vyuha/notes/.claude_commands_implement.md.md`
44
+
45
+ ### How to write notes
46
+
47
+ **Append** a tagged block to the note file (create the file if it doesn't exist):
48
+
49
+ ```markdown
50
+ ## [TICK-NNN]
51
+ - <factual constraint 1>
52
+ - <factual constraint 2>
53
+ ```
54
+
55
+ Rules:
56
+ - Write **factual constraints only**: "X fails if Y", "always do Z before W", "field X must be non-null or parser crashes"
57
+ - **Max 5 bullets per ticket per file** — be terse
58
+ - If nothing non-obvious was learned about a file, **write nothing** (omit the block entirely for that file)
59
+ - Do not repeat what the ticket spec already says; write only what surprised you or would trip up the next agent
60
+
61
+ ### Escalation rule
62
+
63
+ | Type of learning | Where it goes |
64
+ |---|---|
65
+ | File-specific or ephemeral (implementation detail, edge case in one file) | `.vyuha/notes/<flat_path>.md` only |
66
+ | Project-wide convention discovered during implementation | Append a proposal to `.vyuha/pending-globals.md` (also gitignored) with the ticket ID and rationale |
67
+
68
+ **Never write to `CLAUDE.md` autonomously.** Only a human may promote a proposal from `pending-globals.md` into `CLAUDE.md`.
69
+
70
+ ### Example
71
+
72
+ After implementing TICK-042 that touched `src/vyuha/concurrency.py` and `.vyuha.yml`:
73
+
74
+ `.vyuha/notes/src_vyuha_concurrency.py.md`:
75
+ ```markdown
76
+ ## [TICK-042]
77
+ - flock path must be on the same filesystem as the repo root or acquire silently fails
78
+ - always release lock in a trap, not in normal control flow
79
+ ```
80
+
81
+ `.vyuha/notes/.vyuha.yml.md` — omitted (nothing non-obvious learned about the YAML schema)
@@ -0,0 +1,23 @@
1
+ # /integrate — Merge and Promote
2
+
3
+ Integration ritual for code-complete tickets.
4
+
5
+ ```bash
6
+ # 1. Review what's code_complete
7
+ vyuha board
8
+
9
+ # 2. For each code_complete ticket:
10
+ vyuha review TICK-NNN
11
+ vyuha merge TICK-NNN
12
+
13
+ # 3. Check pipeline status
14
+ vyuha pipeline-status
15
+
16
+ # 4. Promote to an environment (manual envs only):
17
+ vyuha promote <env-name>
18
+
19
+ # 5. If feature-flagged, enable in the target environment:
20
+ vyuha flag enable <flag-name> --env <env-name>
21
+ ```
22
+
23
+ For auto-trigger environments (hook-driven), the pipeline handles promotion automatically.
@@ -0,0 +1,7 @@
1
+ # /next-ticket — Recommend Next Ticket
2
+
3
+ Runs `vyuha next` to recommend the highest-priority unblocked ticket(s), respecting `depends_on` and the `touches` lock so parallel agents don't collide.
4
+
5
+ ```bash
6
+ vyuha next
7
+ ```
@@ -0,0 +1,392 @@
1
+ # /orchestrate — Clear the Board
2
+
3
+ Runs the ticket-processing loop. Pulls touch-disjoint batches from `vyuha next`,
4
+ takes each ticket as far as policy allows **in parallel up to a resource cap**,
5
+ and repeats until no eligible tickets remain.
6
+
7
+ **Usage:** `/orchestrate [--max N] [--dry-run] [--human-review final|per_ticket|none]`
8
+
9
+ This skill coordinates the run. It never edits code itself — it dispatches per-ticket
10
+ subagents and runs the CLI verbs between them.
11
+
12
+ ---
13
+
14
+ ## 0. Preflight — single-orchestrator guard
15
+
16
+ Only one orchestrator may run per repo. A second one would double the live agent count
17
+ and blow past the rate-limit / GPU cap (each orchestrator enforces `max_parallel`
18
+ independently, with no cross-process coordination).
19
+
20
+ The check-and-set, stale-lock reclaim, and atomicity (`flock`) live in `concurrency.py`;
21
+ the skill calls the verb with its own shell PID (`$$`):
22
+
23
+ ```bash
24
+ vyuha orchestrator-lock acquire --pid $$ || exit 1 # refuses if a live orchestrator holds it
25
+ trap 'vyuha orchestrator-lock release --pid $$' EXIT # release on exit/error/interrupt
26
+ ```
27
+
28
+ > A stale lock (holder process dead) is reclaimed automatically. To inspect without
29
+ > claiming, run `vyuha orchestrator-lock status`; to override a wedged lock, add `--force`.
30
+
31
+ ---
32
+
33
+ ## 1. Resolve the concurrency cap
34
+
35
+ The cap is the **resource gate**; `vyuha next` is the **correctness gate**. The
36
+ effective batch size each round is `min(eligible_disjoint_tickets, max_parallel)`.
37
+
38
+ Resolve `max_parallel` in this order (first hit wins):
39
+
40
+ 1. `--max N` flag on this invocation.
41
+ 2. `executors.<executor>.max_parallel` in `.vyuha.yml` for the active `executor`.
42
+ 3. Top-level `max_parallel` in `.vyuha.yml`.
43
+ 4. Built-in default: **2**.
44
+
45
+ ```yaml
46
+ # .vyuha.yml
47
+ executor: claude
48
+ max_parallel: 2 # global default
49
+ executors:
50
+ claude: { max_parallel: 3 } # cloud → bounded by API rate limits
51
+ local: { max_parallel: 1 } # single-GPU → effectively sequential
52
+ ```
53
+
54
+ Reminder on semantics: the executor value is an **override**, not additive.
55
+ `local: 1` runs one ticket at a time on purpose; raise it only when your local server
56
+ batches (e.g. vLLM continuous batching).
57
+
58
+ ---
59
+
60
+ ## 2. The loop
61
+
62
+ ```
63
+ repeat:
64
+ batch_json = `vyuha --json next`
65
+ candidates = [batch_json.next] + batch_json.peers # already touch-disjoint
66
+ if candidates is empty: break # no eligible tickets remain
67
+ batch = candidates[:max_parallel] # apply resource cap
68
+ run every ticket in `batch` IN PARALLEL (one subagent each)
69
+ collect finished tickets; as a slot frees, the loop's next round refills it
70
+ ```
71
+
72
+ Use a **worker-pool / semaphore**, not blind fan-out: keep at most `max_parallel`
73
+ subagents live at once and pull the next candidate as each finishes. Do **not** spawn the
74
+ whole board and wait. `vyuha next` only ever returns a disjoint set, so re-querying
75
+ each round naturally respects the `touches` lock as tickets enter/leave flight.
76
+
77
+ ### Prior agent notes injection
78
+
79
+ Before dispatching the subagent for a ticket, collect any notes left by previous agents
80
+ for files this ticket will touch.
81
+
82
+ **Step 1 — collect notes**
83
+
84
+ For each path in `ticket.touches`, derive the flat filename:
85
+ - Replace every `/` in the path with `_`
86
+ - Read `.vyuha/notes/<flat_path>.md` if it exists; silently skip if missing
87
+
88
+ **Step 2 — build the injection**
89
+
90
+ Concatenate all non-empty note file contents. If the result is non-empty, prepend it to
91
+ the agent prompt as a dedicated section:
92
+
93
+ ```
94
+ ## Prior agent notes
95
+
96
+ <concatenated note file contents>
97
+ ```
98
+
99
+ If no note files exist (or all are empty), **omit the section entirely** — do not add a
100
+ heading with no content.
101
+
102
+ **Step 3 — dispatch**
103
+
104
+ Pass the (possibly augmented) prompt to the subagent. The injection is executor-agnostic:
105
+ it works the same for `claude-subagent`, `claude-process`, `aider`, and any other
106
+ executor in the dispatch table below.
107
+
108
+ ---
109
+
110
+ ### Per-ticket executor dispatch
111
+
112
+ The executor for each ticket is resolved per-ticket:
113
+
114
+ ```python
115
+ executor = ticket.get('executor') or cfg['executor']
116
+ ```
117
+
118
+ | `executor` value | Dispatch method |
119
+ |---|---|
120
+ | `claude-subagent` (or `claude`) | Task tool (in-process subagent) |
121
+ | `claude-process` | `claude -p <prompt>` subprocess in the ticket's worktree |
122
+ | `aider`, `codex`, `<cmd>` | configured agent as a process in the ticket's worktree |
123
+
124
+ ```
125
+ vyuha start TICK-NNN # claim + worktree (TOCTOU-safe; see below)
126
+ → dispatch per executor (see table above) with prior notes prepended
127
+ vyuha complete TICK-NNN # drift check vs touches + status → code_complete
128
+ → review gate: see §3 below
129
+ vyuha merge TICK-NNN # ff merge → main, worktree removed
130
+ → analytics log: see §2a below (MANDATORY — do not skip)
131
+ ```
132
+
133
+ ### §2a. Analytics logging (mandatory after every merge)
134
+
135
+ Immediately after `vyuha merge TICK-NNN` succeeds, call `vyuha log` with the token
136
+ counts from the task-notification `<usage>` blocks. Do not skip this step — missing
137
+ entries cannot be backfilled accurately later.
138
+
139
+ ```bash
140
+ vyuha log TICK-NNN \
141
+ --tokens <total_subagent_tokens> # sum of implementer + all reviewer usage blocks
142
+ --summary-tokens <summary_tok> # rough: len(agent_result_text) // 4
143
+ --executor claude-subagent \
144
+ --model claude-sonnet-4-6 \
145
+ --tests-passed # include if tests passed in the subagent
146
+ ```
147
+
148
+ **Where to get the numbers:**
149
+ - `total_subagent_tokens`: sum the `subagent_tokens` field from every task-notification
150
+ `<usage>` block for this ticket (implementer + reviewer(s))
151
+ - `summary_tokens`: rough estimate — `len(result_text) // 4` where `result_text` is the
152
+ agent's returned summary string
153
+
154
+ Log immediately; if the merge was done manually (without `vyuha merge`), still call
155
+ `vyuha log` right after the git commit.
156
+
157
+ If `vyuha start` fails with *"grabbed by another session"* or *"conflicts with …"*,
158
+ **skip that ticket this round** and move on — it is not an error, just a lost race or a
159
+ lock. The next `vyuha next` will reflect reality.
160
+
161
+ For `claude-subagent`/`claude`: Give the subagent only the ticket spec and its `touches` —
162
+ not the board state.
163
+
164
+ For `claude-process`: Run `claude -p "<prompt>"` as a subprocess in the ticket's worktree
165
+ (`worktrees/tick-NNN`). The prompt is the same context as what would be given to a Task
166
+ subagent. Capture stdout/stderr; non-zero exit means implementation failed.
167
+
168
+ ---
169
+
170
+ ## 3. Review gate (always runs — agent review at full quality)
171
+
172
+ After `vyuha complete TICK-NNN`, dispatch a **review subagent** using the resolved
173
+ reviewer executor — which may differ from the implementer's executor. Resolve it as:
174
+
175
+ ```python
176
+ reviewer = ticket.get('reviewer') or cfg.get('reviewer') or cfg['executor']
177
+ ```
178
+
179
+ Resolution order (first non-empty value wins):
180
+ 1. Ticket-level `reviewer` field in frontmatter (per-ticket override)
181
+ 2. Project-level `reviewer` in `.vyuha.yml` (project-wide reviewer default)
182
+ 3. Project-level `executor` in `.vyuha.yml` (fallback to implementer's executor)
183
+
184
+ Dispatch the review subagent using the resolved `reviewer` value, **not** the
185
+ implementer's executor. This allows, for example, a `claude-process` project to use
186
+ `claude-subagent` for reviews, or a specific ticket to route its review to `human`.
187
+
188
+ ### What to give the reviewer
189
+
190
+ ```
191
+ Ticket spec:
192
+ id: TICK-NNN
193
+ title: <title>
194
+ close_criteria: <close_criteria>
195
+ touches: [<files>]
196
+
197
+ Diff (branch vs main):
198
+ <output of: git diff main...tick-nnn>
199
+ ```
200
+
201
+ ### What the reviewer returns
202
+
203
+ A JSON object on stdout:
204
+ ```json
205
+ {
206
+ "verdict": "approved" | "changes_requested",
207
+ "summary": "<one-line verdict summary>",
208
+ "findings": ["<finding 1>", "<finding 2>"]
209
+ }
210
+ ```
211
+
212
+ ### How the orchestrator calls the CLI
213
+
214
+ ```bash
215
+ # Parse the JSON verdict and call:
216
+ vyuha review TICK-NNN \
217
+ --verdict <verdict> \
218
+ --summary "<summary>" \
219
+ --findings "<newline-joined findings>"
220
+ ```
221
+
222
+ `vyuha review --verdict approved` → flips ticket to `in_review`, stores
223
+ `review_verdict` and `review_summary` in frontmatter, appends findings under
224
+ `## Review Findings` in the ticket body.
225
+
226
+ `vyuha review --verdict changes_requested` → stores fields, exits non-zero,
227
+ **leaves ticket at `code_complete`**. The orchestrator treats this ticket as
228
+ blocked for that batch round.
229
+
230
+ ### Policy on changes_requested
231
+
232
+ - Leave the ticket at `code_complete` with the findings stored.
233
+ - Continue the rest of the batch — do not halt the whole run.
234
+ - Report blocked tickets in the end-of-run summary (§6).
235
+ - Do **not** auto-retry the implementation; a human should inspect first.
236
+
237
+ ---
238
+
239
+ ## 4. Rate-limit / load handling (set the cap optimistically)
240
+ <!-- was §3 before the review gate was added as §3 -->
241
+
242
+ So you can set `max_parallel` to the cap rather than guessing low:
243
+
244
+ - On HTTP **429 / rate-limit** from a subagent: respect `Retry-After`, exponential
245
+ backoff with jitter, then retry that ticket. Do **not** fail the batch.
246
+ - If 429s persist across a round, **shrink the live worker count by 1** (adaptive
247
+ throttle) and log it; recover upward after a clean round.
248
+ - On a **local** executor, OOM/timeout is the signal instead — lower the cap, never retry
249
+ blindly into the same wall.
250
+
251
+ ---
252
+
253
+ ## 5. Review policy (human gates only — agent review ALWAYS runs)
254
+
255
+ Set per-batch via `--human-review`, default `final`. Agent review at full quality runs on
256
+ **every** ticket regardless.
257
+
258
+ | Mode | Agent review | Human gate |
259
+ |---|---|---|
260
+ | `per_ticket` | full quality | stop each ticket at `in_review` for a human |
261
+ | `final` (default) | full quality | one human pass over the whole batch at the end |
262
+ | `none` | full quality | none — pre-vetted/trusted runs only |
263
+
264
+ `none` does not mean unreviewed; it means no *human* gate.
265
+
266
+ ---
267
+
268
+ ## 5a. Watch daemon spawn on exit (TICK-019 / TICK-023)
269
+
270
+ After the run loop exits — whether the board is empty or only blocked/in-review
271
+ tickets remain — check for tickets still at `in_review` status.
272
+
273
+ **If any `in_review` tickets exist:**
274
+
275
+ 1. Check whether a watcher is already running:
276
+ ```bash
277
+ vyuha watch --status
278
+ ```
279
+ 2. If not running, spawn a detached background watcher using the `spawn_detached`
280
+ helper from `vyuha.lifecycle`. This is platform-agnostic Python — no `nohup`,
281
+ no `&`, no shell syntax:
282
+ ```python
283
+ from vyuha.lifecycle import spawn_detached
284
+ from pathlib import Path
285
+ import sys
286
+
287
+ log_path = repo_root / ".vyuha" / "watch.log"
288
+ pid = spawn_detached([sys.executable, "-m", "vyuha", "watch"], log_path)
289
+ print(f"[orchestrate] watch daemon started (pid {pid}) — will merge approved PRs in background")
290
+ ```
291
+ The orchestrator's `spawn_watch_daemon(repo_root)` function wraps this exactly.
292
+ 3. If already running, skip spawn and note it in the summary.
293
+
294
+ **End-of-run summary line (when daemon spawned or already running):**
295
+ ```
296
+ [waiting] N ticket(s) in review — watch daemon running (pid NNN)
297
+ ```
298
+
299
+ **If no `in_review` tickets:** do not spawn the watcher.
300
+
301
+ The watcher polls every 60 seconds, calls `vyuha merge` on APPROVED PRs, and exits
302
+ when no `in_review` tickets with a `pr_number` remain.
303
+
304
+ ---
305
+
306
+ ## 7. Context hygiene — keep the main session slim
307
+
308
+ The orchestrator runs in the main Claude session. Every tool result that lands here
309
+ consumes context that is never reclaimed. Subagents exist precisely to keep heavy
310
+ content out of this session. Violating these rules causes the main context to fill
311
+ faster than the board clears, eventually forcing a summarisation mid-run.
312
+
313
+ ### Rules
314
+
315
+ **`vyuha start` — suppress the ticket echo**
316
+
317
+ `vyuha start` prints the full ticket spec to stdout. Capture only the first 3 lines
318
+ (worktree path / branch / "Started"):
319
+
320
+ ```bash
321
+ vyuha start TICK-NNN 2>&1 | head -3
322
+ ```
323
+
324
+ **Reviewer subagents — never relay diffs through main context**
325
+
326
+ Do NOT fetch `git diff main...tick-NNN` in the main session and paste it into the
327
+ reviewer prompt. Instead, tell the reviewer where to look:
328
+
329
+ ```
330
+ Read the diff yourself:
331
+ git -C /home/.../worktrees/tick-NNN diff main...tick-NNN
332
+ Do not ask me to provide it — run the command directly.
333
+ ```
334
+
335
+ This keeps the diff bytes in the subagent's context, not here.
336
+
337
+ **Reviewer subagents — read worktree files, not main-repo files**
338
+
339
+ Reviewer agents that need to read source files MUST be told the worktree path
340
+ explicitly. Agents that default to the main repo see pre-merge state and produce
341
+ false `changes_requested` verdicts. Always include in every reviewer prompt:
342
+
343
+ ```
344
+ Work from the worktree at: /home/.../worktrees/tick-NNN
345
+ Do NOT read files from the main repo path.
346
+ ```
347
+
348
+ **Notes files — bounded by design**
349
+
350
+ Notes files are written only on ticket hibernation (interrupted executor sessions).
351
+ Each hibernation overwrites the file (not appends), and diffs are truncated at 30 KB
352
+ at write time. Notes files are therefore always small and safe to inject as-is.
353
+
354
+ **`vyuha next` / `vyuha board` — use sparingly**
355
+
356
+ Call `vyuha --json next` once per loop iteration. Do not call `vyuha board` mid-loop
357
+ unless diagnosing a problem — the JSON output from `next` has everything needed.
358
+
359
+ ### Symptoms of drift
360
+
361
+ If the main context is above ~40 % mid-run, check:
362
+ 1. Were recent `vyuha start` outputs unsuppressed?
363
+ 2. Did a reviewer prompt contain an inline diff?
364
+ 3. Was a large notes file read into context?
365
+
366
+ Correct forward; do not restart the run.
367
+
368
+ ---
369
+
370
+ ## 6. Stop conditions
371
+
372
+ - `vyuha next` returns no candidates → **no eligible tickets remain**, exit cleanly.
373
+ - Any ticket fails review (`changes_requested`) → leave at `code_complete` (§3), continue
374
+ rest, report blocked tickets at the end.
375
+ - Any ticket with `--human-review per_ticket` approved → stops at `in_review` for a human.
376
+ - Interrupt / error → release the orchestrator lock (§0 trap) and report what merged,
377
+ what is in flight, and what remains.
378
+
379
+ End every run with a summary: merged, blocked/in-review, skipped (lost races), remaining.
380
+
381
+ ---
382
+
383
+ ## Notes / open design points
384
+
385
+ - **`vyuha next` returns one disjoint batch, not a `--limit`.** The skill applies the
386
+ `max_parallel` slice itself. A future `vyuha next --limit N` would let the CLI enforce
387
+ the cap (testable without an LLM in the loop).
388
+ - **The single-orchestrator lock is advisory** (PID file, §0) but now hardened in
389
+ `concurrency.py` (TICK-009 / DECISIONS F14): atomic check-and-set under an `flock`, with
390
+ stale-lock reclaim, exposed via `vyuha orchestrator-lock`. The per-ticket claim also
391
+ takes an `flock` around its read→write→commit window (`claim_lock`), closing the residual
392
+ TOCTOU gap — git's `index.lock` only serialized the status commit, not the whole claim.
@@ -0,0 +1,7 @@
1
+ # /tickets — Ticket Board
2
+
3
+ Runs `vyuha board` and displays all tickets grouped by status, plus the environment pipeline.
4
+
5
+ ```bash
6
+ vyuha board
7
+ ```
@@ -0,0 +1,63 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: ["**"]
6
+ pull_request:
7
+ branches: ["**"]
8
+
9
+ jobs:
10
+ test:
11
+ name: Test (${{ matrix.os }}, Python ${{ matrix.python-version }})
12
+ runs-on: ${{ matrix.os }}
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ os: [ubuntu-latest, macos-latest, windows-latest]
17
+ python-version: ["3.11"]
18
+
19
+ steps:
20
+ - uses: actions/checkout@v5
21
+
22
+ - name: Set up Python ${{ matrix.python-version }}
23
+ uses: actions/setup-python@v6
24
+ with:
25
+ python-version: ${{ matrix.python-version }}
26
+
27
+ - name: Install dependencies
28
+ run: pip install -e .[dev]
29
+
30
+ - name: Run tests
31
+ if: runner.os != 'Windows'
32
+ run: python ci/run_pytest.py
33
+
34
+ - name: Run tests
35
+ if: runner.os == 'Windows'
36
+ shell: cmd
37
+ run: python ci/run_pytest.py
38
+
39
+ smoke-windows:
40
+ name: Windows runtime smoke (Python ${{ matrix.python-version }})
41
+ runs-on: windows-latest
42
+ strategy:
43
+ fail-fast: false
44
+ matrix:
45
+ python-version: ["3.11"]
46
+
47
+ steps:
48
+ - uses: actions/checkout@v5
49
+
50
+ - name: Set up Python ${{ matrix.python-version }}
51
+ uses: actions/setup-python@v6
52
+ with:
53
+ python-version: ${{ matrix.python-version }}
54
+
55
+ - name: Install dependencies
56
+ run: pip install -e .[dev]
57
+
58
+ # Unmocked end-to-end exercise of the OS boundaries the unit suite mocks/skips:
59
+ # detached spawn (CREATE_NEW_PROCESS_GROUP), os.kill SIGTERM (TerminateProcess),
60
+ # the os.kill liveness probe, portalocker flock, and a real `vyuha init` run.
61
+ - name: Run runtime smoke test
62
+ shell: cmd
63
+ run: python ci/smoke_windows.py
vyuha-0.1.0/.gitignore ADDED
@@ -0,0 +1,30 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ *.egg
6
+ dist/
7
+ build/
8
+ venv/
9
+ .venv/
10
+
11
+ # Vyuha local state
12
+ .vyuha.yml
13
+ .vyuha/*
14
+ !.vyuha/notes/
15
+ .vyuha/notes/*
16
+ !.vyuha/notes/.gitkeep
17
+ worktrees/
18
+ *-context-log.jsonl
19
+
20
+ # Claude Code harness files
21
+ HANDOFF.md
22
+ next-session-prompt.md
23
+ AUTONOMOUS_SDLC_PLATFORM_REVIEW.md
24
+ TICK-017-complete.txt
25
+ .claude/auto-continue.md
26
+ .claude/settings.local.json
27
+ .claude/settings.example.json
28
+ .claude/standing-instructions.md
29
+ .claude/stop-failure-events.jsonl
30
+ .claude/statusline-quota-cache.sh
File without changes
@@ -0,0 +1,65 @@
1
+ # .vyuha.yml — project configuration for vyuha
2
+ # Copy this file to .vyuha.yml in your repo root and edit to taste.
3
+ # Or run `vyuha init` to generate a config interactively.
4
+
5
+ ticket_prefix: TICK # TICK-NNN, FEAT-NNN, BUG-NNN, TASK-NNN, etc.
6
+ tickets_dir: .vyuha/tickets
7
+ worktrees_dir: .vyuha/worktrees
8
+
9
+ # Who writes the code
10
+ executor: claude # claude | claude-subagent | claude-process | aider | openhands | codex | ollama
11
+
12
+ # Who reviews the code (optional — defaults to executor if omitted).
13
+ # Set to a different executor for model review, or `human` to pause after
14
+ # completion until a person records an explicit verdict.
15
+ # reviewer: claude
16
+
17
+ # Max tickets the orchestrator runs in parallel.
18
+ # Effective batch = min(touch-disjoint candidates, max_parallel)
19
+ max_parallel: 2
20
+
21
+ # Per-executor overrides (replace the global, not additive).
22
+ # `flags` are prepended to the executor command when dispatching a ticket.
23
+ # The flags below enable headless/autonomous operation — remove them if you
24
+ # want the executor to prompt for approval on each action (supervised mode).
25
+ executors:
26
+ claude: { max_parallel: 3, flags: ["--dangerously-skip-permissions"] }
27
+ aider: { max_parallel: 1, flags: ["--yes-always"] }
28
+ codex: { max_parallel: 3, flags: ["--approval-policy=never"] }
29
+ ollama: { max_parallel: 1, models: { implement: llama3.1, review: qwen2.5-coder } }
30
+
31
+ # Files/patterns where overlapping tickets cannot run in parallel.
32
+ # Leave empty if your project has no shared core files.
33
+ core_files: []
34
+ core_patterns: []
35
+
36
+ # Statuses during which a ticket's `touches` stay locked (held until merge).
37
+ lock_statuses: [in_progress, code_complete, in_review]
38
+
39
+ # ── Feature flags (optional) ─────────────────────────────────────────────────
40
+ # Remove this section if you do not use feature flags.
41
+ flag_file: ~/.vyuha/feature_flags.json
42
+
43
+ # ── Deployment pipeline (optional) ───────────────────────────────────────────
44
+ # Remove this section for projects with no deployment pipeline (libraries,
45
+ # research, open-source). Add one entry per environment in promotion order.
46
+ environments:
47
+ - name: staging
48
+ branch: staging
49
+ from: main # base branch for pending-diff + promotion
50
+ trigger: manual # manual | auto (auto = hook-driven, vyuha reports only)
51
+ sync: ff-only # ff-only | merge-no-ff
52
+ guard_script: null # path to script; exit 1 blocks promote
53
+ pre_promote: [] # scripts to run before promote
54
+ post_promote: [] # scripts to run after promote
55
+ flag_file: ~/.vyuha/staging.feature_flags.json
56
+
57
+ - name: production
58
+ branch: production
59
+ from: main
60
+ trigger: manual
61
+ sync: ff-only
62
+ guard_script: null
63
+ pre_promote: []
64
+ post_promote: []
65
+ flag_file: ~/.vyuha/feature_flags.json