claude-dev-env 8.85.3 → 8.87.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.
- package/.agents/skills/deepen/SKILL.md +5 -21
- package/.agents/skills/efficient-review/README.md +44 -0
- package/.agents/skills/efficient-review/SKILL.md +14 -61
- package/.agents/skills/efficient-review/reference/criteria.md +21 -0
- package/.agents/skills/efficient-review/tools/__init__.py +1 -0
- package/.agents/skills/efficient-review/tools/config/__init__.py +1 -0
- package/.agents/skills/efficient-review/tools/config/efficient_review_constants.py +28 -0
- package/.agents/skills/efficient-review/tools/efficient_review.py +34 -0
- package/.agents/skills/efficient-review/tools/efficient_review_plan.py +95 -0
- package/.agents/skills/efficient-review/tools/tests/test_review_plan.py +94 -0
- package/.agents/skills/search-before-acting/SKILL.md +4 -3
- package/.agents/skills/search-before-acting/playbooks/build.md +1 -1
- package/.agents/skills/search-before-acting/playbooks/plan-or-log.md +1 -1
- package/.agents/skills/search-before-acting/references/report-shape.md +1 -1
- package/bin/codex-skill-load-block.mjs +4 -4
- package/bin/install.prune.test.mjs +10 -4
- package/commands/deepen.md +3 -8
- package/docs/account-broker.md +2 -2
- package/docs/codex-accounts.md +1 -1
- package/docs/decisions/deepstack-gate.md +28 -0
- package/docs/rule-guides/agent-board.md +2 -2
- package/docs/rule-guides/explore-thoroughly.md +2 -2
- package/docs/rule-guides/features-start-with-an-eval.md +2 -2
- package/docs/second-claude-account.md +1 -1
- package/hooks/features/session-context.md +1 -1
- package/hooks/hooks_constants/deepen_first_prompt_constants.py +60 -0
- package/hooks/hooks_constants/haiku_spawn_slim_gate_constants.py +47 -7
- package/hooks/session/deepen_first_prompt.py +31 -7
- package/hooks/session/deepen_role_gate.py +171 -0
- package/hooks/session/fixtures/deepstack_replay.json +15 -0
- package/hooks/session/grade_deepstack_replay.py +78 -0
- package/hooks/session/test_deepen_first_prompt.py +127 -23
- package/hooks/session/test_grade_deepstack_replay.py +47 -0
- package/package.json +1 -1
- package/rules/agent-board.md +1 -1
- package/rules/index.md +2 -2
- package/scripts/account_broker.py +1 -1
- package/scripts/account_broker_support.py +3 -3
- package/scripts/ci/install-playtest.mjs +3 -0
- package/scripts/codex_account_choice.py +5 -5
- package/scripts/dev_env_scripts_constants/codex_account_constants.py +3 -3
- package/scripts/test_codex_account_choice.py +1 -1
- package/.agents/skills/efficient-review/defaults.json +0 -12
- package/.agents/skills/efficient-review/reference/cloud-session.md +0 -13
|
@@ -2,35 +2,19 @@
|
|
|
2
2
|
name: deepen
|
|
3
3
|
description: >-
|
|
4
4
|
Deepen a first user task before work starts. Triggers: /deepen, deepen this
|
|
5
|
-
task, first-task deepening, Cursor Cloud launch prompt.
|
|
5
|
+
task, first-task deepening, Cursor Cloud launch prompt. DeepStack intake
|
|
6
|
+
holds the contract.
|
|
6
7
|
---
|
|
7
8
|
|
|
8
9
|
# deepen
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
## When this applies
|
|
13
|
-
|
|
14
|
-
- An interactive first user task on Claude Code, Cursor, or Codex
|
|
15
|
-
- `/deepen` with a task in the arguments
|
|
16
|
-
- Cursor Cloud, where user `~/.cursor/hooks.json` does not run and `sessionStart` is deferred, so the launch prompt is already sent
|
|
11
|
+
On a first task, `/deepen` plus a task, or a routine wake that has work, read DeepStack intake and follow it: [intake](https://github.com/jl-cmd-projects/DeepStack/blob/main/plugins/deepstack/skills/deepstack-mode/references/intake.md).
|
|
17
12
|
|
|
18
13
|
Skip when the prompt already carries `CDE_DEEPEN:v1`, when the text is a thanks or yes/no or status line, when it is a slash command other than `/deepen`, when it is a `/loop` or helper report, or when it is a spawn rewrite that already starts with the poteto-mode prefix.
|
|
19
14
|
|
|
20
15
|
A prompt that is only `/deepen` with no task is skipped. `/deepen` plus a task deepens the remainder.
|
|
21
16
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
1. What a top person in that field would do that this prompt omitted.
|
|
25
|
-
2. The raw source to start from.
|
|
26
|
-
3. The methods and tools they would use.
|
|
27
|
-
4. What besides the agent or Jon would show the result is right.
|
|
28
|
-
|
|
29
|
-
Then rewrite the user prompt to ask for exactly that job. Put `CDE_DEEPEN:v1` at the top.
|
|
30
|
-
|
|
31
|
-
## How to deepen
|
|
32
|
-
|
|
33
|
-
Read the task. Name the field. Fill the four answers from the checkout, the docs, and the tools already in the tree. Keep the rewrite shorter than a new spec. The worker should start from the raw source and finish at the proof.
|
|
17
|
+
The deepening pass writes the worker prompt and stops. The worker runs that prompt.
|
|
34
18
|
|
|
35
19
|
When you spawn a helper to fill the four answers, that helper's prompt starts with `CDE_DEEPEN_AGENT` so the first-task hook leaves it alone.
|
|
36
20
|
|
|
@@ -38,5 +22,5 @@ When you spawn a helper to fill the four answers, that helper's prompt starts wi
|
|
|
38
22
|
|
|
39
23
|
- Claude desktop and CLI: a `prompt.submit` mod rewrites the visible text. The Python `UserPromptSubmit` hook is silent when that mod is on outside a cloud session.
|
|
40
24
|
- Claude cloud and Codex local: the Python hook injects `additionalContext`. Command hooks cannot replace the prompt string.
|
|
41
|
-
- Cursor Cloud: run
|
|
25
|
+
- Cursor Cloud: run DeepStack intake on the launch prompt. The host adapter for the three lines and the refusal lives with that host. This package keeps the gate.
|
|
42
26
|
- Codex cloud orchestration skips command hooks. Local Codex only.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# One installed copy
|
|
2
|
+
|
|
3
|
+
This package holds the one copy of efficient-review, at `packages/claude-dev-env/.agents/skills/efficient-review/`. A fresh install copies that directory to `~/.claude/skills/efficient-review` and `~/.agents/skills/efficient-review`.
|
|
4
|
+
|
|
5
|
+
A session in any repository runs the review from that installed directory. It does not check out a second repository, name a workflow, or read a credential.
|
|
6
|
+
|
|
7
|
+
## Plan
|
|
8
|
+
|
|
9
|
+
From the skill directory:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
python -m tools.efficient_review plan
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
On Claude, `CLAUDECODE` or `CLAUDE_CODE_ENTRYPOINT` is set and Cursor and Codex markers are absent. The plan selects haiku and the slim profile from `hooks_constants.haiku_spawn_slim_gate_constants`, and prints the headless command and its environment. Run that command. Send the review task on standard input. The criteria are in [reference/criteria.md](reference/criteria.md).
|
|
16
|
+
|
|
17
|
+
On any other platform, including a plain shell, the plan defers the model. The running agent follows [SKILL.md](SKILL.md) and picks the model.
|
|
18
|
+
|
|
19
|
+
The constants module is the copy installed with this package's hooks, at `hooks/hooks_constants/haiku_spawn_slim_gate_constants.py` next to the skills directory, or inside a checkout of this package. The plan does not carry a second profile.
|
|
20
|
+
|
|
21
|
+
## A local job in another repository
|
|
22
|
+
|
|
23
|
+
A repository that wants a job to run the review writes that job itself. This package does not ship one. The job runs the same plan from the installed skill directory, then follows [SKILL.md](SKILL.md).
|
|
24
|
+
|
|
25
|
+
```yaml
|
|
26
|
+
- name: Plan the review
|
|
27
|
+
working-directory: the installed skill directory
|
|
28
|
+
run: python -m tools.efficient_review plan
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## What a consuming repository deletes
|
|
32
|
+
|
|
33
|
+
Delete the vendored skill and the runner that existed only to launch it:
|
|
34
|
+
|
|
35
|
+
- `.claude/skills/efficient-review/`
|
|
36
|
+
- `tools/efficient_review.py`
|
|
37
|
+
- `tools/efficient_review_launch.py`
|
|
38
|
+
- `tools/efficient_review_request.py`
|
|
39
|
+
- `tools/config/efficient_review_constants.py`
|
|
40
|
+
- `.claude/hooks/efficient_review_model_gate.py`
|
|
41
|
+
- `.claude/hooks/efficient_review_model_gate.sh`
|
|
42
|
+
- `.claude/hooks/config/efficient_review_model_gate_constants.py`
|
|
43
|
+
|
|
44
|
+
Also delete a vendored slice of `tools/review_profile`, `tools/review_command`, `tools/review_rules`, `tools/review_stream`, and `tools/review_codex` when that slice exists only so the old runner could import it. Delete a settings file whose keys named a workflow, a checkout credential, a roster, or a broker. Keep `tools/review_model_eval` when the repository still grades reviews with it.
|
|
@@ -1,79 +1,32 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: efficient-review
|
|
3
3
|
description: >-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"haiku review of this branch".
|
|
4
|
+
Review the current branch from the installed skill. On Claude, the plan
|
|
5
|
+
selects haiku and the slim profile. On any other platform, the running agent
|
|
6
|
+
follows the criteria and picks the model. Triggers: /efficient-review,
|
|
7
|
+
"efficient review", "cheap review".
|
|
9
8
|
---
|
|
10
9
|
|
|
11
10
|
# Efficient review
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
Review the current branch with the criteria in [reference/criteria.md](reference/criteria.md). From this directory, run `python -m tools.efficient_review plan`. The plan names the runtime. This skill makes no network call.
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
A blank argument comes from [`defaults.json`](defaults.json).
|
|
14
|
+
## Claude
|
|
17
15
|
|
|
18
|
-
|
|
16
|
+
When the plan runtime is `claude`, the model is haiku and the profile is the slim profile in `hooks_constants.haiku_spawn_slim_gate_constants`. Run the printed command and send the review task on standard input. See [reference/criteria.md](reference/criteria.md).
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
## Other platforms
|
|
21
19
|
|
|
22
|
-
|
|
20
|
+
When the plan runtime is `other`, the model is deferred. The running agent applies [reference/criteria.md](reference/criteria.md) and picks the model.
|
|
23
21
|
|
|
24
|
-
##
|
|
22
|
+
## Loop
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
| Subcommand | Action |
|
|
29
|
-
|---|---|
|
|
30
|
-
| `plan` | Prints the mode, account, model family, harness, effort, level, base, and the prompt. |
|
|
31
|
-
| `accounts` | Lists the Claude accounts a headless run can name. |
|
|
32
|
-
| `run` | Runs a headless or auto review and prints the review, the served models, and the saved file. |
|
|
33
|
-
|
|
34
|
-
## Modes
|
|
35
|
-
|
|
36
|
-
| Mode | Picked when | Account |
|
|
37
|
-
|---|---|---|
|
|
38
|
-
| auto | No mode word and no account. The word `auto` picks it too. | The account broker picks it. Ask nothing. |
|
|
39
|
-
| headless | The word `headless`, or an account launcher name. | Required. With no account named, ask for one. |
|
|
40
|
-
|
|
41
|
-
A model is a family name: haiku, sonnet, opus, sol, or luna. The planner refuses a versioned model ID. `codex review` takes no level, so the planner refuses `level=` with sol or luna.
|
|
42
|
-
|
|
43
|
-
## 1. Headless mode with no account
|
|
44
|
-
|
|
45
|
-
Run `python -m tools.efficient_review accounts`. Ask with the session's question tool, one option per listed account, and wait for the answer. The answer is the account. On the machine that holds the launchers, the list comes from the `claude-*.cmd` launchers, without `claude-base`, `claude-raw`, and `claude-kimi`. In the cloud the list is the known roster.
|
|
46
|
-
|
|
47
|
-
## 2. Headless or auto on that machine
|
|
48
|
-
|
|
49
|
-
Run `python -m tools.efficient_review run <arguments> --repository <checkout>`. When the checkout has no launcher folder, go to step 3.
|
|
50
|
-
|
|
51
|
-
- It builds the slim profile from `tools.review_profile` into a temp folder.
|
|
52
|
-
- Auto asks `account_broker.py choose --product claude` for the account.
|
|
53
|
-
- It runs the account launcher with `-p`, the model alias, the effort, the profile arguments, and the environment. The system prompt file holds the review rules from the checkout that contains the runner, and the code standards. The prompt and the diff against the base go on standard input.
|
|
54
|
-
- A sol or luna family runs `codex review` on the newest slug of that family. The log prints that slug.
|
|
55
|
-
- It prints the review, the served models from the stream's `modelUsage` keys, and the saved file. The review and its record go to a temp folder outside the repository.
|
|
56
|
-
|
|
57
|
-
## 3. Headless or auto from a cloud session
|
|
58
|
-
|
|
59
|
-
The cloud container has no other Claude accounts, so the review runs on the agent-pc runner. Read [reference/cloud-session.md](reference/cloud-session.md).
|
|
24
|
+
Check each finding against the code. Fix every one that holds. Run the review again until a pass reports none. The steps are in [reference/criteria.md](reference/criteria.md).
|
|
60
25
|
|
|
61
26
|
## Reading guide
|
|
62
27
|
|
|
63
28
|
| File | What it does |
|
|
64
29
|
|---|---|
|
|
65
|
-
| [
|
|
66
|
-
| [
|
|
67
|
-
|
|
68
|
-
## Common pitfalls
|
|
69
|
-
|
|
70
|
-
- **Picking a stronger model after several passes.** Fix the findings and run haiku again.
|
|
71
|
-
- **Setting a valid finding aside.** Check each finding against the code. Fix every one that holds in the same branch, even when it reaches files the diff did not touch. Answer only the findings that fail the check, with the file and line that rules each out.
|
|
72
|
-
- **Asking which model to use.** The answer is haiku. When the owner names another family, run it without a confirmation question.
|
|
73
|
-
- **Spawning the review as a subagent.** The review loses the slim profile. Run it headless.
|
|
74
|
-
- **Dispatching from the branch under review.** The workflow runs only from `main`.
|
|
75
|
-
|
|
76
|
-
## Out of scope
|
|
77
|
-
|
|
78
|
-
- The `validator` default stays `off`.
|
|
79
|
-
- A fixer step after the review. The skill has no fixer step.
|
|
30
|
+
| [README.md](README.md) | How a session loads this copy, and the shape of a local job a repository may write. |
|
|
31
|
+
| [reference/criteria.md](reference/criteria.md) | The review criteria, the finding block, and the loop. |
|
|
32
|
+
| [tools/efficient_review.py](tools/efficient_review.py) | `plan` prints the runtime selection. |
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Review criteria
|
|
2
|
+
|
|
3
|
+
Apply these to the diff. Report a finding only after checking it against the code.
|
|
4
|
+
|
|
5
|
+
- Review supported behavior and the changed repository contract. Current instructions override a stale copy. A contract change is not a defect because an older rule differs.
|
|
6
|
+
- Name a reachable caller, a supported input, and an observable failure for each defect.
|
|
7
|
+
- Check command flags, the environment, the pipeline, and the executable path before calling a command read-only.
|
|
8
|
+
- Security and atomicity findings need deployment and trust-boundary evidence.
|
|
9
|
+
- Coverage advice is separate from a demonstrated defect.
|
|
10
|
+
- A changed context file that passes the context budget and still carries detail a pointer should hold is a finding.
|
|
11
|
+
- Bind a delayed event, a cancellation, and review evidence to the full candidate head.
|
|
12
|
+
- A finished review can contain findings. A resolved thread, a timeout, or a quota notice does not prove a repair.
|
|
13
|
+
- Only a verified pass on the current head supports admission.
|
|
14
|
+
|
|
15
|
+
## Finding block
|
|
16
|
+
|
|
17
|
+
An empty list is a valid review. End with a json block. Each finding has `file`, `line`, `priority`, `summary`, and `failure_scenario`. Priority 0 blocks the merge. Priority 1 is fixed before the merge. Priority 2 can follow the merge. Priority 3 is a style nit.
|
|
18
|
+
|
|
19
|
+
## Loop
|
|
20
|
+
|
|
21
|
+
Fix every finding that holds, including a file the diff did not touch. Then run the review again. Stop when a pass reports no finding that holds.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Plan one efficient-review run from the installed skill."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Constants for the efficient-review plan."""
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Paths and runtime markers for the efficient-review plan."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
SKILL_ROOT = Path(__file__).resolve().parents[2]
|
|
8
|
+
GATE_CONSTANTS_FILENAME = "haiku_spawn_slim_gate_constants.py"
|
|
9
|
+
GATE_MODULE_NAME = "haiku_spawn_slim_gate_constants"
|
|
10
|
+
HOOKS_DIRECTORY_NAME = "hooks"
|
|
11
|
+
HOOKS_CONSTANTS_DIRECTORY_NAME = "hooks_constants"
|
|
12
|
+
ALL_HOOKS_PARENT_STEPS = (1, 2)
|
|
13
|
+
USER_HOME_PARENT_STEP = 2
|
|
14
|
+
CLAUDE_HOME_DIRECTORY_NAME = ".claude"
|
|
15
|
+
ALL_CLAUDE_HOST_VARIABLES = ("CLAUDECODE", "CLAUDE_CODE_ENTRYPOINT")
|
|
16
|
+
ALL_OTHER_HOST_VARIABLES = (
|
|
17
|
+
"CURSOR_AGENT",
|
|
18
|
+
"CURSOR_TRACE_ID",
|
|
19
|
+
"CODEX_HOME",
|
|
20
|
+
"CODEX_CI",
|
|
21
|
+
)
|
|
22
|
+
RUNTIME_CLAUDE = "claude"
|
|
23
|
+
RUNTIME_OTHER = "other"
|
|
24
|
+
MODEL_DEFERRED = "deferred"
|
|
25
|
+
PROFILE_DEFERRED = "deferred"
|
|
26
|
+
JSON_INDENT = 2
|
|
27
|
+
PLAN_COMMAND = "plan"
|
|
28
|
+
TEXT_ENCODING = "utf-8"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Plan one /efficient-review run from the installed skill."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
from typing import TextIO
|
|
10
|
+
|
|
11
|
+
from tools.config import efficient_review_constants as c
|
|
12
|
+
from tools.efficient_review_plan import plan_review
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main(all_arguments: list[str], plan_stream: TextIO) -> int:
|
|
16
|
+
"""Print the runtime selection for one review.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
all_arguments: Command-line arguments, without the program name.
|
|
20
|
+
plan_stream: Where the plan JSON is written.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
Zero when the plan prints.
|
|
24
|
+
"""
|
|
25
|
+
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
26
|
+
subcommands = parser.add_subparsers(dest="command", required=True)
|
|
27
|
+
subcommands.add_parser(c.PLAN_COMMAND)
|
|
28
|
+
parser.parse_args(all_arguments)
|
|
29
|
+
plan_stream.write(json.dumps(plan_review(os.environ), indent=c.JSON_INDENT) + "\n")
|
|
30
|
+
return 0
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
if __name__ == "__main__":
|
|
34
|
+
sys.exit(main(sys.argv[1:], sys.stdout))
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Choose haiku and the slim profile on Claude, and defer the model elsewhere."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import importlib.util
|
|
6
|
+
from collections.abc import Mapping
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from types import ModuleType
|
|
9
|
+
|
|
10
|
+
from tools.config import efficient_review_constants as c
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ReviewPlanFatal(RuntimeError):
|
|
14
|
+
"""The slim-profile constants module is not installed beside this skill."""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def plan_review(all_environment: Mapping[str, str]) -> dict[str, object]:
|
|
18
|
+
"""Return the runtime selection for one review.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
all_environment: The process environment.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
Claude selects haiku and the slim profile. Every other runtime defers the model.
|
|
25
|
+
"""
|
|
26
|
+
if _is_claude_runtime(all_environment):
|
|
27
|
+
return _claude_plan(_load_gate_constants())
|
|
28
|
+
return {
|
|
29
|
+
"runtime": c.RUNTIME_OTHER,
|
|
30
|
+
"model": c.MODEL_DEFERRED,
|
|
31
|
+
"profile": c.PROFILE_DEFERRED,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _is_claude_runtime(all_environment: Mapping[str, str]) -> bool:
|
|
36
|
+
if any(all_environment.get(each_name) for each_name in c.ALL_OTHER_HOST_VARIABLES):
|
|
37
|
+
return False
|
|
38
|
+
return any(all_environment.get(each_name) for each_name in c.ALL_CLAUDE_HOST_VARIABLES)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _claude_plan(gate_constants: ModuleType) -> dict[str, object]:
|
|
42
|
+
return {
|
|
43
|
+
"runtime": c.RUNTIME_CLAUDE,
|
|
44
|
+
"model": gate_constants.HAIKU_MODEL_FAMILY,
|
|
45
|
+
"profile": gate_constants.SLIM_PROFILE_NAME,
|
|
46
|
+
"command": [
|
|
47
|
+
gate_constants.SLIM_PROFILE_EXECUTABLE,
|
|
48
|
+
*gate_constants.ALL_SLIM_PROFILE_ARGUMENTS,
|
|
49
|
+
],
|
|
50
|
+
"environment": list(gate_constants.ALL_SLIM_PROFILE_ENVIRONMENT),
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _load_gate_constants() -> ModuleType:
|
|
55
|
+
constants_path = _gate_constants_path()
|
|
56
|
+
spec = importlib.util.spec_from_file_location(c.GATE_MODULE_NAME, constants_path)
|
|
57
|
+
if spec is None or spec.loader is None:
|
|
58
|
+
raise ReviewPlanFatal(f"cannot load slim profile constants from {constants_path}")
|
|
59
|
+
module = importlib.util.module_from_spec(spec)
|
|
60
|
+
spec.loader.exec_module(module)
|
|
61
|
+
return module
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _gate_constants_path() -> Path:
|
|
65
|
+
for each_candidate in _candidate_paths(c.SKILL_ROOT):
|
|
66
|
+
if each_candidate.is_file():
|
|
67
|
+
return each_candidate
|
|
68
|
+
raise ReviewPlanFatal(
|
|
69
|
+
"the slim profile constants are missing; install the package hooks next to this skill"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _candidate_paths(skill_root: Path) -> tuple[Path, ...]:
|
|
74
|
+
relative_parts = (
|
|
75
|
+
c.HOOKS_DIRECTORY_NAME,
|
|
76
|
+
c.HOOKS_CONSTANTS_DIRECTORY_NAME,
|
|
77
|
+
c.GATE_CONSTANTS_FILENAME,
|
|
78
|
+
)
|
|
79
|
+
all_candidates = [
|
|
80
|
+
skill_root.parents[each_step].joinpath(*relative_parts)
|
|
81
|
+
for each_step in c.ALL_HOOKS_PARENT_STEPS
|
|
82
|
+
if len(skill_root.parents) > each_step
|
|
83
|
+
]
|
|
84
|
+
user_home = _parent_at(skill_root, c.USER_HOME_PARENT_STEP)
|
|
85
|
+
if user_home is not None:
|
|
86
|
+
all_candidates.append(
|
|
87
|
+
user_home.joinpath(c.CLAUDE_HOME_DIRECTORY_NAME, *relative_parts)
|
|
88
|
+
)
|
|
89
|
+
return tuple(all_candidates)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _parent_at(start: Path, steps: int) -> Path | None:
|
|
93
|
+
if len(start.parents) <= steps:
|
|
94
|
+
return None
|
|
95
|
+
return start.parents[steps]
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""The plan selects haiku on Claude and defers the model on every other runtime."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
SKILL_ROOT = Path(__file__).resolve().parents[2]
|
|
12
|
+
if str(SKILL_ROOT) not in sys.path:
|
|
13
|
+
sys.path.insert(0, str(SKILL_ROOT))
|
|
14
|
+
|
|
15
|
+
from tools.config import efficient_review_constants as c
|
|
16
|
+
from tools.efficient_review_plan import plan_review
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_should_load_the_slim_profile_from_the_claude_home(
|
|
20
|
+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
21
|
+
) -> None:
|
|
22
|
+
skill_root = tmp_path / ".agents" / "skills" / "efficient-review"
|
|
23
|
+
skill_root.mkdir(parents=True)
|
|
24
|
+
constants_path = (
|
|
25
|
+
tmp_path
|
|
26
|
+
/ ".claude"
|
|
27
|
+
/ "hooks"
|
|
28
|
+
/ "hooks_constants"
|
|
29
|
+
/ c.GATE_CONSTANTS_FILENAME
|
|
30
|
+
)
|
|
31
|
+
constants_path.parent.mkdir(parents=True)
|
|
32
|
+
source = (
|
|
33
|
+
SKILL_ROOT.parents[2]
|
|
34
|
+
/ "hooks"
|
|
35
|
+
/ "hooks_constants"
|
|
36
|
+
/ c.GATE_CONSTANTS_FILENAME
|
|
37
|
+
)
|
|
38
|
+
constants_path.write_text(source.read_text(encoding=c.TEXT_ENCODING), encoding=c.TEXT_ENCODING)
|
|
39
|
+
monkeypatch.setattr(c, "SKILL_ROOT", skill_root)
|
|
40
|
+
plan = plan_review({"CLAUDECODE": "1"})
|
|
41
|
+
assert plan["model"] == "haiku"
|
|
42
|
+
assert plan["profile"] == "slim"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
FORBIDDEN_SNIPPETS = (
|
|
46
|
+
"dispatch_repository",
|
|
47
|
+
"dispatch_workflow",
|
|
48
|
+
"dispatch_ref",
|
|
49
|
+
"read_token",
|
|
50
|
+
"results_branch",
|
|
51
|
+
"account_broker",
|
|
52
|
+
"urllib",
|
|
53
|
+
"socket",
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_should_select_haiku_and_the_slim_profile_on_claude() -> None:
|
|
58
|
+
plan = plan_review({"CLAUDECODE": "1"})
|
|
59
|
+
assert plan["runtime"] == "claude"
|
|
60
|
+
assert plan["model"] == "haiku"
|
|
61
|
+
assert plan["profile"] == "slim"
|
|
62
|
+
assert plan["command"][0] == "claude"
|
|
63
|
+
assert "--model" in plan["command"]
|
|
64
|
+
assert plan["command"][plan["command"].index("--model") + 1] == "haiku"
|
|
65
|
+
assert "CLAUDE_CODE_DISABLE_CLAUDE_MDS=1" in plan["environment"]
|
|
66
|
+
serialized = json.dumps(plan)
|
|
67
|
+
assert "token" not in serialized
|
|
68
|
+
assert "dispatch" not in serialized
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_should_defer_the_model_when_the_runtime_is_not_claude() -> None:
|
|
72
|
+
for each_environment in (
|
|
73
|
+
{},
|
|
74
|
+
{"CURSOR_AGENT": "1"},
|
|
75
|
+
{"CODEX_HOME": "/tmp/codex"},
|
|
76
|
+
{"CURSOR_AGENT": "1", "CLAUDECODE": "1"},
|
|
77
|
+
):
|
|
78
|
+
plan = plan_review(each_environment)
|
|
79
|
+
assert plan == {
|
|
80
|
+
"runtime": "other",
|
|
81
|
+
"model": "deferred",
|
|
82
|
+
"profile": "deferred",
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_should_keep_dispatch_and_network_out_of_the_skill() -> None:
|
|
87
|
+
all_texts = [
|
|
88
|
+
each_path.read_text(encoding=c.TEXT_ENCODING)
|
|
89
|
+
for each_path in SKILL_ROOT.rglob("*.py")
|
|
90
|
+
if "tests" not in each_path.parts
|
|
91
|
+
]
|
|
92
|
+
combined = "\n".join(all_texts)
|
|
93
|
+
for each_snippet in FORBIDDEN_SNIPPETS:
|
|
94
|
+
assert each_snippet not in combined
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
name: search-before-acting
|
|
3
3
|
description: >-
|
|
4
4
|
Search for what already does an ask before logging, planning, delegating,
|
|
5
|
-
or building it, then report what exists in four points
|
|
6
|
-
|
|
5
|
+
or building it, then report what exists in four points. When the role-level
|
|
6
|
+
job is already authorized, continue that job. Use when a user asks for new
|
|
7
|
+
or changed behavior, a tool, a check,
|
|
7
8
|
a workflow, a report, a tracker entry, or a plan, and before writing a
|
|
8
9
|
brief for a worker.
|
|
9
10
|
---
|
|
@@ -17,7 +18,7 @@ The user should hear about work that already does their ask before anyone duplic
|
|
|
17
18
|
1. Restate the ask as the outcome the user wants, in their words.
|
|
18
19
|
2. Search every place in [`references/search-places.md`](references/search-places.md) that this session can reach. Note each place you could not reach.
|
|
19
20
|
3. Sort each hit as full, partial, or related. A hit is full when it already produces the outcome from step 1.
|
|
20
|
-
4. When any hit is full or partial,
|
|
21
|
+
4. When any hit is full or partial, send the four-point report from [`references/report-shape.md`](references/report-shape.md). When the role-level job is already authorized, continue that job. When it is not, wait for the user. When a hit is full, tell the user they already have it.
|
|
21
22
|
5. When nothing is found, say where you looked in one line, then continue with the playbook below.
|
|
22
23
|
|
|
23
24
|
## Playbooks
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Use this playbook before you build or change code, a hook, a skill, a rule, a workflow, or config for an ask.
|
|
4
4
|
|
|
5
5
|
1. Run the skill steps. Search the places in [`../references/search-places.md`](../references/search-places.md), with production config and launcher options first when the ask names a running system.
|
|
6
|
-
2. When a hit is full or partial, send the [report](../references/report-shape.md)
|
|
6
|
+
2. When a hit is full or partial, send the [report](../references/report-shape.md). When the role-level job is already authorized, continue that job. When it is not, wait for the user's answer.
|
|
7
7
|
3. When the user says go, build only the missing part from point 3 of the report. Extend the existing piece where it lives. Start a new piece only when the existing one cannot hold the addition, and say why in the pull request.
|
|
8
8
|
4. When nothing exists, follow `prefer-existing-tools.md` to check open-source options, then build.
|
|
9
9
|
5. Add an "Existing work" section to the pull request body. List each hit with its link or `file:line` and what the pull request adds on top of it. When nothing was found, say so and name the places searched. The pull request gate denies a body without this section.
|
|
@@ -4,6 +4,6 @@ Use this playbook before you add an ask to a tracker, open an issue or card for
|
|
|
4
4
|
|
|
5
5
|
1. Run the skill steps. Search open and closed tracker entries for the ask first, then the rest of [`../references/search-places.md`](../references/search-places.md).
|
|
6
6
|
2. When a tracker entry already names the ask, update that entry and link it. Skip the new entry.
|
|
7
|
-
3. When code, config, or a merged pull request already does the ask in full or in part, send the [report](../references/report-shape.md)
|
|
7
|
+
3. When code, config, or a merged pull request already does the ask in full or in part, send the [report](../references/report-shape.md). When the role-level job is already authorized, continue that job. When it is not, wait for the user before you log or plan.
|
|
8
8
|
4. When the user says go, log or plan only the missing part. Link each existing piece in the entry or plan, so the reader starts from what is live.
|
|
9
9
|
5. When nothing exists, write the entry or plan with one line that names the places searched.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Report shape
|
|
2
2
|
|
|
3
|
-
Send this report when the search finds something that does the ask in full or in part. Send it before any log entry, plan, brief, or edit,
|
|
3
|
+
Send this report when the search finds something that does the ask in full or in part. Send it before any log entry, plan, brief, or edit. When the role-level job is already authorized, continue that job. When it is not, wait for the user.
|
|
4
4
|
|
|
5
5
|
1. **What exists and where.** Each hit with a link or `file:line`, and whether it is live.
|
|
6
6
|
2. **What it covers of the ask.** The parts of the outcome it already produces.
|
|
@@ -11,10 +11,10 @@ export const DEEPEN_GUIDANCE_BLOCK_START = '<!-- claude-dev-env deepen: start --
|
|
|
11
11
|
export const DEEPEN_GUIDANCE_BLOCK_END = '<!-- claude-dev-env deepen: end -->';
|
|
12
12
|
export const DEEPEN_GUIDANCE_TEXT = [
|
|
13
13
|
'Deepen the first interactive user task before any work starts.',
|
|
14
|
-
'
|
|
15
|
-
'
|
|
16
|
-
'On demand, follow the
|
|
17
|
-
'Cursor Cloud
|
|
14
|
+
'Follow DeepStack intake. Write SCOPE (role), EXAMPLES (illustration only), and ZOOM-IN BLOCKER before any plan.',
|
|
15
|
+
'The worker prompt carries the marker CDE_DEEPEN:v1 on line 1 and the SCOPE (role) line.',
|
|
16
|
+
'On demand, follow the DeepStack skill or /deepen with a task.',
|
|
17
|
+
'Cursor Cloud registers the DeepStack SessionStart hook and the first-task gate. Use DeepStack intake on the launch prompt.',
|
|
18
18
|
'Codex cloud orchestration skips command hooks. This block is the local Codex instruction.',
|
|
19
19
|
].join('\n');
|
|
20
20
|
|
|
@@ -813,10 +813,16 @@ test('a fresh scoped core install includes efficient-review', () => {
|
|
|
813
813
|
assert.match(skillText, /^name: efficient-review$/m);
|
|
814
814
|
assert.match(skillText, /\/efficient-review/);
|
|
815
815
|
assert.equal(readManifest(sandbox.manifestPath).skills.includes('efficient-review'), true);
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
);
|
|
816
|
+
const skillDirectory = join(sandbox.skillsDirectory, 'efficient-review');
|
|
817
|
+
assert.equal(existsSync(join(skillDirectory, 'README.md')), true);
|
|
818
|
+
assert.equal(existsSync(join(skillDirectory, 'reference', 'criteria.md')), true);
|
|
819
|
+
assert.equal(existsSync(join(skillDirectory, 'tools', 'efficient_review.py')), true);
|
|
820
|
+
assert.equal(existsSync(join(skillDirectory, 'settings.json')), false);
|
|
821
|
+
assert.equal(existsSync(join(skillDirectory, 'reference', 'cloud-session.md')), false);
|
|
822
|
+
const readme = readFileSync(join(skillDirectory, 'README.md'), 'utf8');
|
|
823
|
+
assert.match(readme, /python -m tools\.efficient_review plan/);
|
|
824
|
+
assert.equal(readme.includes('dispatch_repository'), false);
|
|
825
|
+
assert.equal(readme.includes('read_token'), false);
|
|
820
826
|
} finally {
|
|
821
827
|
rmSync(sandbox.homeDirectory, { recursive: true, force: true });
|
|
822
828
|
}
|
package/commands/deepen.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Deepen a task into the
|
|
2
|
+
description: Deepen a task into the standing job before work starts
|
|
3
3
|
argument-hint: [task to deepen]
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -7,13 +7,8 @@ Deepen this task before any work starts: `$ARGUMENTS`
|
|
|
7
7
|
|
|
8
8
|
When `$ARGUMENTS` is empty, ask the user to paste the task and stop.
|
|
9
9
|
|
|
10
|
-
When `$ARGUMENTS` holds a task,
|
|
10
|
+
When `$ARGUMENTS` holds a task, follow DeepStack intake at https://github.com/jl-cmd-projects/DeepStack/blob/main/plugins/deepstack/skills/deepstack-mode/references/intake.md.
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
2. The raw source to start from.
|
|
14
|
-
3. The methods and tools they would use.
|
|
15
|
-
4. What besides the agent or Jon would show the result is right.
|
|
16
|
-
|
|
17
|
-
Rewrite the task so it asks for exactly that job. Put `CDE_DEEPEN:v1` at the top of the rewrite. Then do only that job.
|
|
12
|
+
Write `SCOPE (role):`, `EXAMPLES (illustration only):`, and `ZOOM-IN BLOCKER:` before any plan. Put `CDE_DEEPEN:v1` on line 1 of the worker prompt and carry the scope line there. The deepening pass writes that prompt and stops.
|
|
18
13
|
|
|
19
14
|
Skip this command when the prompt already carries `CDE_DEEPEN:v1`.
|
package/docs/account-broker.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Account broker
|
|
2
2
|
|
|
3
|
-
`account_broker.py` reads the Claude and Codex account
|
|
3
|
+
`account_broker.py` reads the Claude and Codex account lists, checks each account's session and weekly usage, and chooses an account with room. It does not select a model or sleep. A Codex decision names the `normal` or `luna` tier for the caller.
|
|
4
4
|
|
|
5
5
|
Claude's main home is `~/.claude`. Its `claude-chain.json` file contains a `chain` list; each entry's `credentials_path` field identifies the credentials file whose parent is that account's home folder. The optional `extra-profiles.json` file in the main home lists additional profile names.
|
|
6
6
|
|
|
7
7
|
The optional `claude-account-order.json` file in the main home sets the Claude pick priority. It is a JSON list of account names, first choice first, such as `["claude-second", "claude"]`. An entry matches an account's name, its command, or its `claude-<name>` launcher, and `claude` names the main account. A new job goes to the first listed account with room. When no listed account has room, the broker picks the unlisted account with the most room, and it waits when no account has room. A resumed session stays on its bound account while that account has room. A listed name absent from the roster is skipped. Without the file, every job goes to the account with the most room. Edit the file to change the order; the next pick reads it.
|
|
8
8
|
|
|
9
|
-
Codex uses its configured account
|
|
9
|
+
Codex uses its configured account list. When no Codex roster is configured, the broker chooses the default Codex home. A new Codex job goes to an account on a Pro plan before any other account in the same tier. The plan comes from the account's meter reply, and `ALL_PRO_PLAN_TYPES` lists the Pro plans: `pro`, `prolite`, and `promax`. Among accounts of the same kind, the one with the most room wins. A Pro account below the `normal` floor still loses to any account with room in the `normal` tier.
|
|
10
10
|
|
|
11
11
|
## Commands
|
|
12
12
|
|
package/docs/codex-accounts.md
CHANGED
|
@@ -16,7 +16,7 @@ A job asks the broker which account to use.
|
|
|
16
16
|
|
|
17
17
|
## Names and order
|
|
18
18
|
|
|
19
|
-
The account
|
|
19
|
+
The account list names the accounts and their order. It comes from the
|
|
20
20
|
`CODEX_ACCOUNT_PROFILES` environment variable, a comma-separated list such as
|
|
21
21
|
`alpha,beta`. When that variable is unset or empty, the roster is the saved list
|
|
22
22
|
in `account-launchers.json` under the profiles root. When neither exists, the
|