opencode-codeops 1.8.1 → 1.10.0

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 (61) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +18 -0
  3. package/_shared/quality-profile.md +9 -0
  4. package/_shared/reasoning-effort.md +135 -0
  5. package/_shared/workspace-hygiene.md +53 -0
  6. package/agent-templates/codebase-scout.md +6 -0
  7. package/agent-templates/concurrency-auditor.md +7 -0
  8. package/agent-templates/design-challenger.md +6 -0
  9. package/agent-templates/domain-specialist-executor.md +6 -0
  10. package/agent-templates/domain-specialist-reviewer.md +6 -0
  11. package/agent-templates/financial-integrity-auditor.md +7 -0
  12. package/agent-templates/perf-auditor.md +6 -0
  13. package/agent-templates/phase-reviewer.md +6 -0
  14. package/agent-templates/plan-task-executor-opus.md +6 -0
  15. package/agent-templates/plan-task-executor.md +6 -0
  16. package/agent-templates/preflight-auditor.md +6 -0
  17. package/agent-templates/security-auditor.md +6 -0
  18. package/agent-templates/semantics-reviewer.md +7 -0
  19. package/agent-templates/spec-test-author.md +6 -0
  20. package/agents/concurrency-auditor.md +7 -0
  21. package/agents/correctness-reviewer.md +6 -0
  22. package/agents/demanding-executor.md +6 -0
  23. package/agents/design-challenger.md +6 -0
  24. package/agents/executor.md +6 -0
  25. package/agents/explorer.md +6 -0
  26. package/agents/financial-integrity-auditor.md +7 -0
  27. package/agents/performance-auditor.md +6 -0
  28. package/agents/preflight-auditor.md +6 -0
  29. package/agents/security-auditor.md +6 -0
  30. package/agents/semantics-reviewer.md +7 -0
  31. package/agents/spec-test-author.md +6 -0
  32. package/bin/lib/reasoning-effort.d.mts +85 -0
  33. package/bin/lib/reasoning-effort.mjs +331 -0
  34. package/bin/lib/tmp-hygiene.d.mts +38 -0
  35. package/bin/lib/tmp-hygiene.mjs +180 -0
  36. package/package.json +1 -1
  37. package/plugin/index.ts +146 -3
  38. package/scripts/__pycache__/install_agents.cpython-312.pyc +0 -0
  39. package/scripts/codeops_effort.py +216 -0
  40. package/scripts/fixtures/catalog-executor.golden.md +6 -0
  41. package/skills/analyze-project/SKILL.md +8 -0
  42. package/skills/clean-comments/SKILL.md +8 -0
  43. package/skills/exec-plan/SKILL.md +21 -0
  44. package/skills/exec-plan/execution-protocol.md +52 -7
  45. package/skills/git-commit/SKILL.md +11 -2
  46. package/skills/github-issues/SKILL.md +8 -0
  47. package/skills/grill-me/SKILL.md +18 -0
  48. package/skills/make-plan/SKILL.md +25 -0
  49. package/skills/make-plan/templates.md +2 -0
  50. package/skills/make-requirements/SKILL.md +18 -0
  51. package/skills/outcome-review/SKILL.md +8 -0
  52. package/skills/preflight/SKILL.md +18 -0
  53. package/skills/retro-requirements/SKILL.md +18 -0
  54. package/skills/roadmap/SKILL.md +8 -0
  55. package/skills/setup-codeops/SKILL.md +8 -0
  56. package/skills/setup-routing/SKILL.md +10 -0
  57. package/skills/setup-routing/routing.md +16 -1
  58. package/skills/techdocs/SKILL.md +8 -0
  59. package/skills/upgrade-plan/SKILL.md +18 -0
  60. package/standards/coding-standards-full.md +19 -0
  61. package/standards/coding-standards.md +6 -0
package/plugin/index.ts CHANGED
@@ -4,6 +4,20 @@ import { homedir } from "node:os"
4
4
  import { join, dirname } from "node:path"
5
5
  import { fileURLToPath } from "node:url"
6
6
 
7
+ import {
8
+ cleanStaleTmpDirs,
9
+ ensureSessionTmpDir,
10
+ removeSessionTmpDir,
11
+ } from "../bin/lib/tmp-hygiene.mjs"
12
+ import {
13
+ applyEffort,
14
+ findEffortMarker,
15
+ readRoutingReasoning,
16
+ readSessionEffort,
17
+ resolveEffort,
18
+ } from "../bin/lib/reasoning-effort.mjs"
19
+ import type { EffortLevel } from "../bin/lib/reasoning-effort.mjs"
20
+
7
21
  // ---------------------------------------------------------------------------
8
22
  // Package root — resolved at module load time so it is always the plugin's
9
23
  // installed directory, regardless of the working directory at event time.
@@ -43,6 +57,28 @@ const outputStyle = readFileSync(
43
57
  )
44
58
  const standardsText = `${codingStandards}\n\n${outputStyle}`
45
59
 
60
+ // ---------------------------------------------------------------------------
61
+ // Workspace hygiene — the plugin owns one temp directory per session (exported
62
+ // as CODEOPS_TMPDIR) and sweeps directories abandoned by earlier interrupted
63
+ // runs. The sweep runs at most once per plugin process, so spawning many child
64
+ // sessions does not repeat the directory walk.
65
+ // ---------------------------------------------------------------------------
66
+ let sweptStaleTmpDirs = false
67
+
68
+ /**
69
+ * Sweep temp directories abandoned by earlier interrupted runs, once per
70
+ * process. Cleanup is best effort: a failure must never block a session.
71
+ */
72
+ function sweepStaleTmpDirsOnce(): void {
73
+ if (sweptStaleTmpDirs) return
74
+ sweptStaleTmpDirs = true
75
+ try {
76
+ cleanStaleTmpDirs()
77
+ } catch {
78
+ // Best effort only.
79
+ }
80
+ }
81
+
46
82
  // ---------------------------------------------------------------------------
47
83
  // Helper — inject standards into a session without triggering an AI reply.
48
84
  // Uses client.session.prompt with noReply: true (confirmed from OpenCode SDK).
@@ -109,23 +145,69 @@ async function warnOnVersionSkew(
109
145
  }
110
146
  }
111
147
 
148
+ // ---------------------------------------------------------------------------
149
+ // Helper — log one content-free warning. Logging is best effort: a failed log
150
+ // must never break a request.
151
+ // ---------------------------------------------------------------------------
152
+ async function warnContentFree(
153
+ client: Parameters<Plugin>[0]["client"],
154
+ message: string
155
+ ): Promise<void> {
156
+ try {
157
+ await client.app.log({ body: { service: "codeops", level: "warn", message } })
158
+ } catch {
159
+ // Best effort only.
160
+ }
161
+ }
162
+
163
+ // ---------------------------------------------------------------------------
164
+ // Helper — read the project routing config fresh on every request, so an edit
165
+ // applies without restarting the session. Any failure means "no routing".
166
+ // ---------------------------------------------------------------------------
167
+ function readRoutingConfig(directory: string): unknown {
168
+ try {
169
+ return JSON.parse(readFileSync(join(directory, "codeops", "codeops.json"), "utf8"))
170
+ } catch {
171
+ return {}
172
+ }
173
+ }
174
+
112
175
  // ---------------------------------------------------------------------------
113
176
  // CodeOps plugin for OpenCode
114
177
  // Replaces: hooks/hooks.json + hook_session_context.sh + hook_marker_guard.sh
115
178
  // ---------------------------------------------------------------------------
116
179
  export const CodeOpsPlugin: Plugin = async ({ client, directory }) => {
180
+ // Reasoning-effort state lives for the lifetime of this plugin instance:
181
+ // one entry per user message that carried a dispatch marker, plus a
182
+ // deduplication set for unsupported-level warnings.
183
+ const effortMarkers = new Map<string, { sessionID: string; level: EffortLevel }>()
184
+ const warnedEffortLevels = new Set<string>()
185
+
117
186
  return {
118
187
  // -----------------------------------------------------------------------
119
188
  // Hook 1 & 2: inject standards on session.created and session.compacted.
120
189
  // Both are dispatched via the generic event hook.
121
190
  // session.created → new session (Codex: startup)
122
191
  // session.compacted → after compact (Codex: resume|compact)
192
+ // Also the hygiene lifecycle: a new top-level session sweeps abandoned
193
+ // temp directories once, and a deleted session's temp directory is removed.
123
194
  // -----------------------------------------------------------------------
124
195
  event: async ({ event }) => {
125
196
  if (event.type === "session.created") {
126
- const sessionId: string = (event.properties as { info: { id: string } }).info.id
127
- await injectStandards(client, sessionId)
197
+ const info = (event.properties as { info: { id: string; parentID?: string } }).info
198
+ await injectStandards(client, info.id)
128
199
  await warnOnVersionSkew(client, directory)
200
+ if (!info.parentID) sweepStaleTmpDirsOnce()
201
+ } else if (event.type === "session.deleted") {
202
+ const info = (event.properties as { info: { id: string } }).info
203
+ removeSessionTmpDir(info.id)
204
+ try {
205
+ for (const [messageID, entry] of effortMarkers) {
206
+ if (entry.sessionID === info.id) effortMarkers.delete(messageID)
207
+ }
208
+ } catch {
209
+ await warnContentFree(client, "Could not clear captured reasoning-effort markers.")
210
+ }
129
211
  } else if (event.type === "session.compacted") {
130
212
  const sessionId: string = (event.properties as { sessionID: string }).sessionID
131
213
  await injectStandards(client, sessionId)
@@ -148,9 +230,16 @@ export const CodeOpsPlugin: Plugin = async ({ client, directory }) => {
148
230
  // scripts as: python3 "${CODEOPS_PLUGIN_ROOT}/scripts/codeops_plan.py"
149
231
  // The value is the package root (parent of this plugin/ directory), which
150
232
  // is where skills/, scripts/, and the other shipped assets live.
233
+ // CODEOPS_TMPDIR is the session's directory under the CodeOps temp root;
234
+ // skills and agents put every scratch file there and delete it when done.
151
235
  // -----------------------------------------------------------------------
152
- "shell.env": async (_input, output) => {
236
+ "shell.env": async (input, output) => {
153
237
  output.env.CODEOPS_PLUGIN_ROOT = PACKAGE_ROOT
238
+ try {
239
+ output.env.CODEOPS_TMPDIR = ensureSessionTmpDir(input.sessionID)
240
+ } catch {
241
+ // Best effort: a temp-directory failure must never block a shell.
242
+ }
154
243
  },
155
244
 
156
245
  // -----------------------------------------------------------------------
@@ -177,5 +266,59 @@ export const CodeOpsPlugin: Plugin = async ({ client, directory }) => {
177
266
  )
178
267
  }
179
268
  },
269
+
270
+ // -----------------------------------------------------------------------
271
+ // Hook 6: capture a dispatch marker from an incoming user message. The
272
+ // marker travels in the dispatch packet text; storing it by message id
273
+ // lets the later chat.params hook apply it to the same request.
274
+ // -----------------------------------------------------------------------
275
+ "chat.message": async (input, output) => {
276
+ try {
277
+ const texts = output.parts.map((part) =>
278
+ part?.type === "text" ? part.text : undefined
279
+ )
280
+ const level = findEffortMarker(texts)
281
+ if (level !== undefined) {
282
+ effortMarkers.set(output.message.id, { sessionID: input.sessionID, level })
283
+ }
284
+ } catch {
285
+ await warnContentFree(client, "Could not scan a message for a reasoning-effort marker.")
286
+ }
287
+ },
288
+
289
+ // -----------------------------------------------------------------------
290
+ // Hook 7: resolve the request's reasoning level (dispatch marker, then
291
+ // session flag, then routing default) and merge the model's own variant
292
+ // options. Any failure leaves the request unchanged.
293
+ // -----------------------------------------------------------------------
294
+ "chat.params": async (input, output) => {
295
+ try {
296
+ const stored = effortMarkers.get(input.message.id)
297
+ const marker = stored && stored.sessionID === input.sessionID ? stored.level : undefined
298
+ const session = readSessionEffort(input.sessionID)
299
+ const routing = readRoutingReasoning(readRoutingConfig(directory), input.agent)
300
+ const level = resolveEffort({ marker, session, routing })
301
+ if (level === undefined) return
302
+
303
+ const applied = applyEffort(output.options, level, input.model)
304
+ if (applied === output.options) {
305
+ if (marker !== undefined) {
306
+ const warningKey = `${input.sessionID}:${marker}`
307
+ if (!warnedEffortLevels.has(warningKey)) {
308
+ warnedEffortLevels.add(warningKey)
309
+ await warnContentFree(
310
+ client,
311
+ `Reasoning effort ${marker} is not available for agent ${input.agent}; ` +
312
+ "request left unchanged."
313
+ )
314
+ }
315
+ }
316
+ return
317
+ }
318
+ output.options = applied
319
+ } catch {
320
+ await warnContentFree(client, "Could not apply a reasoning-effort level to a request.")
321
+ }
322
+ },
180
323
  }
181
324
  }
@@ -0,0 +1,216 @@
1
+ #!/usr/bin/env python3
2
+ """Record and clear the opt-in reasoning-effort level for a CodeOps session run.
3
+
4
+ The skills call this helper when a user passes `--auto-effort`. It writes one
5
+ small JSON file inside the session's CodeOps temp directory; the plugin reads
6
+ that file on every request and applies the level. The command fails closed:
7
+ an invalid level or a directory outside the CodeOps temp root exits with
8
+ status 2 and writes nothing.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import argparse
14
+ import json
15
+ import os
16
+ import sys
17
+ import tempfile
18
+ from datetime import datetime, timezone
19
+ from pathlib import Path
20
+
21
+
22
+ #: The only levels a session flag may record.
23
+ EFFORT_LEVELS = ("low", "medium", "high", "max")
24
+
25
+ #: Name of the state file the plugin reads.
26
+ STATE_FILE_NAME = "reasoning-effort.json"
27
+
28
+
29
+ def codeops_tmp_root() -> Path:
30
+ """Return the CodeOps-owned temp root for the active temp directory.
31
+
32
+ The root mirrors the layout `bin/lib/tmp-hygiene.mjs` owns, so the helper
33
+ and the plugin resolve the same per-session directory.
34
+
35
+ Returns:
36
+ Resolved path of the CodeOps temp root.
37
+ """
38
+ return Path(tempfile.gettempdir()).resolve() / "opencode" / "codeops"
39
+
40
+
41
+ def resolve_session_dir(raw_dir: str) -> Path | None:
42
+ """Validate a session directory argument against the CodeOps temp root.
43
+
44
+ A directory is accepted only when it exists, resolves strictly inside the
45
+ CodeOps temp root, and is not the root itself. Symlinks are resolved, so a
46
+ link that points outside the root is rejected.
47
+
48
+ Args:
49
+ raw_dir: The `--dir` argument as provided by the caller.
50
+
51
+ Returns:
52
+ The resolved session directory, or None when it is not acceptable.
53
+ """
54
+ try:
55
+ resolved = Path(raw_dir).resolve(strict=True)
56
+ except (OSError, RuntimeError):
57
+ # RuntimeError covers a symlink loop on Python 3.12, which the
58
+ # filesystem reports as ELOOP rather than a plain OSError.
59
+ return None
60
+ root = codeops_tmp_root()
61
+ if resolved == root or root not in resolved.parents:
62
+ return None
63
+ if not resolved.is_dir():
64
+ return None
65
+ return resolved
66
+
67
+
68
+ def state_path(session_dir: Path) -> Path:
69
+ """Return the state-file path inside a validated session directory.
70
+
71
+ Args:
72
+ session_dir: A directory accepted by `resolve_session_dir`.
73
+
74
+ Returns:
75
+ Path of the reasoning-effort state file.
76
+ """
77
+ return session_dir / STATE_FILE_NAME
78
+
79
+
80
+ def set_level(session_dir: Path, level: str) -> int:
81
+ """Write the session level atomically and report it.
82
+
83
+ The payload is written to a temporary file in the same directory and then
84
+ moved over the final name with `os.replace`, so a reader never observes a
85
+ partially written file.
86
+
87
+ Args:
88
+ session_dir: A validated session directory.
89
+ level: One of `EFFORT_LEVELS`.
90
+
91
+ Returns:
92
+ Process exit code 0.
93
+ """
94
+ payload = {
95
+ "schema": 1,
96
+ "reasoning": level,
97
+ "setAt": datetime.now(timezone.utc).isoformat(timespec="seconds"),
98
+ }
99
+ path = state_path(session_dir)
100
+ descriptor, temporary_name = tempfile.mkstemp(
101
+ prefix=f"{STATE_FILE_NAME}.", suffix=".tmp", dir=session_dir
102
+ )
103
+ try:
104
+ with os.fdopen(descriptor, "w", encoding="utf-8") as handle:
105
+ json.dump(payload, handle, separators=(",", ":"), sort_keys=True)
106
+ handle.write("\n")
107
+ os.replace(temporary_name, path)
108
+ except OSError:
109
+ try:
110
+ os.unlink(temporary_name)
111
+ except OSError:
112
+ pass
113
+ print("Error: could not write the reasoning-effort state file.", file=sys.stderr)
114
+ return 2
115
+ print(f"Reasoning effort set: {level} for this session run.")
116
+ return 0
117
+
118
+
119
+ def clear_level(session_dir: Path) -> int:
120
+ """Remove the session level when present and report the cleanup.
121
+
122
+ Args:
123
+ session_dir: A validated session directory.
124
+
125
+ Returns:
126
+ Process exit code 0.
127
+ """
128
+ try:
129
+ state_path(session_dir).unlink()
130
+ except FileNotFoundError:
131
+ pass
132
+ except OSError:
133
+ print("Error: could not remove the reasoning-effort state file.", file=sys.stderr)
134
+ return 2
135
+ print("Reasoning effort cleared.")
136
+ return 0
137
+
138
+
139
+ def show_status(session_dir: Path) -> int:
140
+ """Print the stored session level, or the empty-state message.
141
+
142
+ Args:
143
+ session_dir: A validated session directory.
144
+
145
+ Returns:
146
+ Process exit code 0.
147
+ """
148
+ level = None
149
+ try:
150
+ payload = json.loads(state_path(session_dir).read_text(encoding="utf-8"))
151
+ if (
152
+ isinstance(payload, dict)
153
+ and payload.get("schema") == 1
154
+ and payload.get("reasoning") in EFFORT_LEVELS
155
+ ):
156
+ level = payload["reasoning"]
157
+ except (OSError, json.JSONDecodeError):
158
+ level = None
159
+ if level is None:
160
+ print("No session reasoning effort set.")
161
+ else:
162
+ print(f"Session reasoning effort: {level}")
163
+ return 0
164
+
165
+
166
+ def parse_args() -> argparse.Namespace:
167
+ """Parse the command-line arguments.
168
+
169
+ Returns:
170
+ The parsed argparse namespace.
171
+ """
172
+ parser = argparse.ArgumentParser(description=__doc__)
173
+ sub = parser.add_subparsers(dest="command", required=True)
174
+
175
+ set_parser = sub.add_parser("set", help="record a session reasoning level")
176
+ set_parser.add_argument("--dir", required=True, help="session temp directory")
177
+ set_parser.add_argument("--reasoning", required=True, help="level to record")
178
+
179
+ clear_parser = sub.add_parser("clear", help="remove the session reasoning level")
180
+ clear_parser.add_argument("--dir", required=True, help="session temp directory")
181
+
182
+ status_parser = sub.add_parser("status", help="print the session reasoning level")
183
+ status_parser.add_argument("--dir", required=True, help="session temp directory")
184
+
185
+ return parser.parse_args()
186
+
187
+
188
+ def main() -> int:
189
+ """Run the requested command.
190
+
191
+ Returns:
192
+ Process exit code: 0 on success, 2 on invalid input.
193
+ """
194
+ args = parse_args()
195
+ session_dir = resolve_session_dir(args.dir)
196
+ if session_dir is None:
197
+ print(
198
+ "Error: --dir must be an existing session directory inside the CodeOps temp root.",
199
+ file=sys.stderr,
200
+ )
201
+ return 2
202
+ if args.command == "set":
203
+ if args.reasoning not in EFFORT_LEVELS:
204
+ print(
205
+ "Error: --reasoning must be one of: " + ", ".join(EFFORT_LEVELS) + ".",
206
+ file=sys.stderr,
207
+ )
208
+ return 2
209
+ return set_level(session_dir, args.reasoning)
210
+ if args.command == "clear":
211
+ return clear_level(session_dir)
212
+ return show_status(session_dir)
213
+
214
+
215
+ if __name__ == "__main__":
216
+ raise SystemExit(main())
@@ -57,3 +57,9 @@ original-goal or smallest-design context blocks execution; report it to the pare
57
57
  exactly what is missing or ambiguous as a blocker — never guess, and never edit the
58
58
  execution plan or roadmap (the parent session owns those and the user conversation).
59
59
  - Report per task, 3-4 lines each: what changed, test status, any blocker.
60
+ - **Workspace hygiene (non-negotiable).** Temporary artifacts you create — verify logs, diffs,
61
+ patches, scratch directories — belong under `$CODEOPS_TMPDIR` when it is set (otherwise the OS
62
+ temp directory), never inside the repository. Delete everything you created before reporting
63
+ done. Never delete user files, versioned artifacts, worktrees, or another session's temporary
64
+ files. If an artifact must outlive the task, name it and say why. Full rules:
65
+ `_shared/workspace-hygiene.md`.
@@ -27,3 +27,11 @@ description: Analyze the current repository and create or refresh concise CodeOp
27
27
  10. When a specialization signal is strong and no specialist covers it, report the candidate with evidence and recommend the `setup-routing` creation flow ([../../_shared/specialist-agents.md](../../_shared/specialist-agents.md)); never write agent files here. Preserve the `<!-- CODEOPS-SPECIALISTS:START -->` / `<!-- CODEOPS-SPECIALISTS:END -->` block byte-for-byte when refreshing the managed section.
28
28
 
29
29
  Keep `AGENTS.md` small. Operational routing belongs in `codeops/codeops.json` or `opencode.json`, not prose.
30
+
31
+ ---
32
+
33
+ > **Workspace hygiene (non-negotiable):** put every temporary artifact this run creates in
34
+ > `$CODEOPS_TMPDIR` (fallback: the OS temp directory), never in the repository, and delete them
35
+ > all before reporting completion. Never delete user files, versioned artifacts, worktrees, or
36
+ > another session's temporary files. Full rules:
37
+ > [_shared/workspace-hygiene.md](../../_shared/workspace-hygiene.md).
@@ -20,3 +20,11 @@ This is a comment-only workflow. Never alter executable tokens, declarations, ty
20
20
  7. Review the diff to prove only comments changed. Run the repository's normal formatter and verification command.
21
21
 
22
22
  Documentation explains the shipped system, not the temporary process that produced it.
23
+
24
+ ---
25
+
26
+ > **Workspace hygiene (non-negotiable):** put every temporary artifact this run creates in
27
+ > `$CODEOPS_TMPDIR` (fallback: the OS temp directory), never in the repository, and delete them
28
+ > all before reporting completion. Never delete user files, versioned artifacts, worktrees, or
29
+ > another session's temporary files. Full rules:
30
+ > [_shared/workspace-hygiene.md](../../_shared/workspace-hygiene.md).
@@ -36,6 +36,18 @@ do not report or implement optional additions raised during execution or review.
36
36
  Exploration may create `SE-*` proposals, but only the user may choose `Keep` and authorize a plan
37
37
  update.
38
38
 
39
+ ## Auto-effort option
40
+
41
+ If `$ARGUMENTS` contains exactly one exact standalone `--auto-effort` or `--auto-effort=<level>`
42
+ token before the first `--` sentinel, remove it before resolving targets, paths, or modes; zero
43
+ occurrences means each phase's `Reasoning:` level is printed as a suggestion only, more than one
44
+ or an invalid level is an argument error; announce
45
+ `Auto-effort active — reasoning <level> applied for this run`; then read and apply
46
+ [../../_shared/reasoning-effort.md](../../_shared/reasoning-effort.md) §Auto-effort option. A bare
47
+ flag follows each phase's suggestion; `--auto-effort=<level>` forces that level for the whole run,
48
+ including every dispatch marker composed during it. The run clears the level before its final
49
+ summary.
50
+
39
51
  Execute the implementation plan at `plans/$ARGUMENTS/99-execution-plan.md`. The first
40
52
  argument is the feature name; an optional flag selects the commit mode.
41
53
 
@@ -267,3 +279,12 @@ Brief rules for verification failure, plan deviation, and mid-task interruption
267
279
  files and use only facts you can read — do not invent settings.
268
280
  - Commit using the `git-commit` skill (commit only) or the `git-commit` skill in push mode (commit + push), or a normal git commit.
269
281
  - Related skills: make-plan (creation), upgrade-plan (outdated plans), preflight, roadmap, techdocs.
282
+ - Cleanup is part of session wrap-up: delete the run's verify logs and scratch per
283
+ [../../_shared/workspace-hygiene.md](../../_shared/workspace-hygiene.md) and report
284
+ `Cleanup: done` in the session summary.
285
+
286
+ > **Workspace hygiene (non-negotiable):** put every temporary artifact this run creates in
287
+ > `$CODEOPS_TMPDIR` (fallback: the OS temp directory), never in the repository, and delete them
288
+ > all before reporting completion. Never delete user files, versioned artifacts, worktrees, or
289
+ > another session's temporary files. Full rules:
290
+ > [_shared/workspace-hygiene.md](../../_shared/workspace-hygiene.md).
@@ -70,6 +70,10 @@ scope baseline; missing mode context fails closed to strict scope.
70
70
  When opt-in outcome metrics are enabled, record only a content-free execution-stage event through
71
71
  `codeops_outcomes.py`; metrics never gate execution.
72
72
 
73
+ When the phase header carries `> **Reasoning**: <level> — <reason>`, record it as the phase's
74
+ advisory level for dispatch markers, inline reporting, and applied-level reporting. It is a
75
+ suggestion: no gate reads it, and its absence means "inherit".
76
+
73
77
  **Spec-author dispatch (profile-gated).** Tasks marked `[spec-author]` dispatch the
74
78
  spec-test-author agent — packet per `_shared/quality-profile.md` — BEFORE any implementation
75
79
  task of that phase, and the red phase is confirmed from its report. A spec test that cannot be
@@ -225,7 +229,8 @@ red-phase, green-phase, session wrap-up — executes with output captured to a t
225
229
  <verify command> > "$VERIFY_LOG" 2>&1
226
230
  ```
227
231
 
228
- (`$VERIFY_LOG` = a file in the session temp/scratchpad dir, e.g. `verify-<task-id>.log`.)
232
+ (`$VERIFY_LOG` = a file under `$CODEOPS_TMPDIR` — or the OS temp directory when it is unset —
233
+ e.g. `verify-<task-id>.log`.)
229
234
 
230
235
  - **PASS** → surface ONE line: `VERIFY PASS (task N.N.N)`, plus the test count if it is
231
236
  extractable from the log tail at no extra cost.
@@ -234,10 +239,11 @@ red-phase, green-phase, session wrap-up — executes with output captured to a t
234
239
  - **Red-phase runs** (spec tests expected to fail) → surface only the failing spec-test
235
240
  names/count confirming the red state — never the full dump.
236
241
 
237
- The full log always remains on disk for the session. If the log location is unwritable, fall
238
- back to running verify plainly ONCE and note the fallback in the session summary. This rule is
239
- about CONTEXT, not rigor: the verify command itself, its scope, and pass/fail gating are
240
- unchanged — and the temp log is read-only evidence, never executed.
242
+ The full log remains on disk until the session wrap-up cleanup deletes it (see
243
+ `_shared/workspace-hygiene.md`); nothing in the transcript depends on it afterward. If the log
244
+ location is unwritable, fall back to running verify plainly ONCE and note the fallback in the
245
+ session summary. This rule is about CONTEXT, not rigor: the verify command itself, its scope, and
246
+ pass/fail gating are unchanged — and the temp log is read-only evidence, never executed.
241
247
 
242
248
  ### Zero-Ambiguity During Execution
243
249
 
@@ -298,12 +304,46 @@ receives nothing else and must not need anything else:
298
304
  - the scope mode (`strict` or `explore`) and confirmed product scope baseline; missing or invalid
299
305
  scope context fails closed to strict mode. Missing or invalid original-goal or smallest-design
300
306
  context blocks dispatch;
301
- - the target file paths and the project's verify command.
307
+ - the target file paths and the project's verify command;
308
+ - the phase's reasoning marker line (`[codeops-effort: <level>]`), resolved from the run's forced
309
+ `--auto-effort=<level>` level, else the phase's `Reasoning:` suggestion; omitted when neither
310
+ exists.
302
311
 
303
312
  Excerpting owned content into a packet is the intended retrieval mechanism, not restatement. The
304
313
  quoted AR/ST/spec content is context for the executor's *understanding* — it must not surface as a
305
314
  citation in shipped code (the executor carries the same doc-standard ban and self-check).
306
315
 
316
+ **Reasoning marker.** Every dispatched unit — executor, reviewer, auditor, spec-test author,
317
+ specialist, or scout — receives one standalone marker line in its packet:
318
+
319
+ ```text
320
+ [codeops-effort: medium]
321
+ ```
322
+
323
+ Place it immediately after the `[codeops-dispatch …]` header for quality agents, or as the first
324
+ line for packets without a header. When neither the forced run level nor the phase suggestion
325
+ exists, add no marker: routing policy still applies, otherwise the child inherits the parent
326
+ variant. The marker is packet context; it never appears in shipped code comments. The
327
+ complexity-gate design challenger is excluded because its independence contract forbids extra
328
+ packet shaping.
329
+
330
+ **Applied-level reporting.** For every dispatch, report the level and its source in the dispatch
331
+ commentary, for example `Dispatch: executor — reasoning: medium (phase suggestion)`,
332
+ `— reasoning: high (routing default)`, or `— inherited`. Reporting is observational; it never
333
+ gates a dispatch.
334
+
335
+ **Inline phases.** When a phase runs inline (the default):
336
+
337
+ 1. Print `Suggested reasoning: <level> — <reason>` before the phase's first task when the phase
338
+ header carries the line.
339
+ 2. Without `--auto-effort`, change nothing else — the session keeps its own variant.
340
+ 3. With `--auto-effort`, set the session level for the phase through
341
+ `python3 "${CODEOPS_PLUGIN_ROOT}/scripts/codeops_effort.py" set --dir "$CODEOPS_TMPDIR" --reasoning <level>`
342
+ and update it when the next phase's suggestion differs; with `--auto-effort=<level>`, set that
343
+ level once and keep it for the whole run. A phase without a `Reasoning:` line leaves the
344
+ session level unchanged.
345
+ 4. When `$CODEOPS_TMPDIR` is empty or the helper fails, print an advise-only note and continue.
346
+
307
347
  **Division of labor.** The PARENT — never the executor — updates `99-execution-plan.md`
308
348
  (two-stage marks), the Progress header, and the roadmap. The executor implements task-by-task,
309
349
  runs verify per the Verify-output capture rule, and reports per task. Mark `[~]` as the executor
@@ -402,7 +442,12 @@ otherwise still `[~]` — with the progress counter and Last Updated stamp curre
402
442
  2. **🚨 First: update `99-execution-plan.md`** with ALL completed tasks (before anything else).
403
443
  3. Run the verify command (output captured per the Verify-output capture rule).
404
444
  4. Handle the commit per the active commit mode (see [commit-modes.md](commit-modes.md)).
405
- 5. Report the session summary (must include `Execution Plan Updated: ✅`).
445
+ 5. If this run set a session level through `--auto-effort`, clear it before the summary:
446
+ `python3 "${CODEOPS_PLUGIN_ROOT}/scripts/codeops_effort.py" clear --dir "$CODEOPS_TMPDIR"`.
447
+ 6. Report the session summary (must include `Execution Plan Updated: ✅`).
448
+ 7. **Cleanup:** delete every temporary artifact this session created — verify logs under
449
+ `$CODEOPS_TMPDIR`, scratch directories, temporary diffs — per
450
+ `_shared/workspace-hygiene.md`, and report `Cleanup: done` or name what was kept and why.
406
451
 
407
452
  ### Session Summary Template
408
453
 
@@ -14,13 +14,14 @@ A request to commit authorizes a local commit only. Push only when the user expl
14
14
  1. Resolve the repository root and inspect `git status --short`, staged/unstaged diffs, and recent commit style.
15
15
  2. If clean, report `nothing to commit` and stop.
16
16
  3. Inspect every untracked file. Stop and ask before staging likely secrets, credentials, build output, large binaries, or unrelated scratch files.
17
- 4. Resolve the authoritative verification command from `AGENTS.md`, CodeOps plan Verify lines, or project manifests. Run it with output captured to a temporary log. On failure, report the failure tail and do not stage or commit.
17
+ 4. Resolve the authoritative verification command from `AGENTS.md`, CodeOps plan Verify lines, or project manifests. Run it with output captured to a log under `$CODEOPS_TMPDIR` (fallback: the OS temp directory), never in the repository. On failure, report the failure tail and do not stage or commit.
18
18
  5. Stage deliberately by explicit paths or coherent groups. Avoid `git add .` when the working directory may be a monorepo subtree or unrelated changes exist.
19
19
  6. Review `git diff --cached --check`, the staged stat, and the staged diff. Ensure the commit contains one coherent purpose and preserves unrelated user changes.
20
- 7. Write a Conventional Commit message to a temporary file and commit with `git commit -F`. Never use an inline multiline message.
20
+ 7. Write a Conventional Commit message to a temporary file under `$CODEOPS_TMPDIR` (fallback: the OS temp directory) and commit with `git commit -F`. Never use an inline multiline message.
21
21
  8. If a commit hook modifies files, inspect and restage only relevant changes, then retry once. Never use `--no-verify` automatically.
22
22
  9. For push mode, fetch/rebase only when appropriate for the branch policy. Stop on conflicts; never resolve ambiguous conflicts automatically. Push normally, never with force.
23
23
  10. Report the resulting commit, verification, and push state.
24
+ 11. Delete the temporary verification log and commit-message file, then report `Cleanup: done` or name what was kept and why.
24
25
 
25
26
  ## Message shape
26
27
 
@@ -33,3 +34,11 @@ type(scope): imperative summary
33
34
  ```
34
35
 
35
36
  Use `feat`, `fix`, `refactor`, `test`, `docs`, or `chore` unless repository guidance defines another convention.
37
+
38
+ ---
39
+
40
+ > **Workspace hygiene (non-negotiable):** put every temporary artifact this run creates in
41
+ > `$CODEOPS_TMPDIR` (fallback: the OS temp directory), never in the repository, and delete them
42
+ > all before reporting completion. Never delete user files, versioned artifacts, worktrees, or
43
+ > another session's temporary files. Full rules:
44
+ > [_shared/workspace-hygiene.md](../../_shared/workspace-hygiene.md).
@@ -36,3 +36,11 @@ For each issue:
36
36
  5. Continue past nonexistent individual issues but record every outcome.
37
37
 
38
38
  Return a per-issue summary. Never create, edit, label, close, reopen, or comment unless the user's request explicitly authorizes that mutation.
39
+
40
+ ---
41
+
42
+ > **Workspace hygiene (non-negotiable):** put every temporary artifact this run creates in
43
+ > `$CODEOPS_TMPDIR` (fallback: the OS temp directory), never in the repository, and delete them
44
+ > all before reporting completion. Never delete user files, versioned artifacts, worktrees, or
45
+ > another session's temporary files. Full rules:
46
+ > [_shared/workspace-hygiene.md](../../_shared/workspace-hygiene.md).
@@ -21,6 +21,16 @@ implementation work begins.
21
21
 
22
22
  > **CodeOps Artifact Schema**: 1
23
23
 
24
+ ## Auto-effort option
25
+
26
+ If `$ARGUMENTS` contains exactly one exact standalone `--auto-effort` or `--auto-effort=<level>`
27
+ token before the first `--` sentinel, remove it before resolving targets, paths, or modes; zero
28
+ occurrences means this skill's recommended level (`high`) is printed as a suggestion only, more
29
+ than one or an invalid level is an argument error; announce
30
+ `Auto-effort active — reasoning <level> applied for this run`; then read and apply
31
+ [../../_shared/reasoning-effort.md](../../_shared/reasoning-effort.md) §Auto-effort option. The
32
+ run clears the level before its final summary.
33
+
24
34
  ## Core Directive
25
35
 
26
36
  > **Interview the user relentlessly about every aspect of the topic until you reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one.**
@@ -340,3 +350,11 @@ grill-me → identify design tree → walk each branch → resolve decisions →
340
350
 
341
351
  **Output:** A shared understanding summary with all decisions, assumptions,
342
352
  constraints, and deferrals — ready to feed into any downstream skill.
353
+
354
+ ---
355
+
356
+ > **Workspace hygiene (non-negotiable):** put every temporary artifact this run creates in
357
+ > `$CODEOPS_TMPDIR` (fallback: the OS temp directory), never in the repository, and delete them
358
+ > all before reporting completion. Never delete user files, versioned artifacts, worktrees, or
359
+ > another session's temporary files. Full rules:
360
+ > [_shared/workspace-hygiene.md](../../_shared/workspace-hygiene.md).