easy-coding-harness 0.8.0 → 0.8.1-beta.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "easy-coding-harness",
3
- "version": "0.8.0",
3
+ "version": "0.8.1-beta.1",
4
4
  "description": "CLI scaffold for installing Easy Coding harness files into agent-native directories.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -13,16 +13,6 @@
13
13
  }
14
14
  ],
15
15
  "UserPromptSubmit": [
16
- {
17
- "matcher": "",
18
- "hooks": [
19
- {
20
- "type": "command",
21
- "command": "{{platform_hook_session_start_command}}",
22
- "timeout": 15000
23
- }
24
- ]
25
- },
26
16
  {
27
17
  "matcher": "",
28
18
  "hooks": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "hooks": {
3
- "UserPromptSubmit": [
3
+ "SessionStart": [
4
4
  {
5
5
  "hooks": [
6
6
  {
@@ -9,7 +9,9 @@
9
9
  "timeout": 10
10
10
  }
11
11
  ]
12
- },
12
+ }
13
+ ],
14
+ "UserPromptSubmit": [
13
15
  {
14
16
  "hooks": [
15
17
  {
@@ -44,10 +44,30 @@ Field whitelist: `mode`, `language`, `test.*`, `build.*`, `lint.*`. Do not inven
44
44
  top-level keys. Do not copy any CLI-owned field (`harness_version`, `agents`, …) into this
45
45
  file.
46
46
 
47
- ## Entry guard (idempotencyrun first)
47
+ ## Project-init preflight (run first read-only)
48
48
 
49
49
  1. Read `.easy-coding/tasks/project-init/task.json`.
50
50
  - File missing → the CLI never ran. Tell the user to run `easy-coding init` first. Stop.
51
+ - File present → record its `status` for the entry dispatch below, but do not start the
52
+ compliance scan or initialization yet.
53
+ 2. Do not call the state API or write any project asset until this file-existence check passes.
54
+
55
+ ## Session path resolution (run after preflight — before any project write)
56
+
57
+ Resolve one stable session path `<P>` and reuse it for the entire skill run:
58
+
59
+ 1. If hook context contains `[easy-coding:session-file:P]`, use that exact path.
60
+ 2. Otherwise run
61
+ `{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py snapshot --agent <agent-id>`
62
+ and use the returned `session_file` as `<P>`. This is the compatibility path for an explicit
63
+ ec-init invocation before the platform has surfaced hook context.
64
+ 3. If snapshot fails or does not return a safe session path, stop before writing any project
65
+ asset and tell the user to enable or approve the platform hooks. Never execute a command with
66
+ the literal placeholder `<P>`.
67
+
68
+ ## Entry dispatch (idempotency — run after session resolution)
69
+
70
+ 1. Use the `status` read during the project-init preflight.
51
71
  - `status == "COMPLETE"` → already initialized. Run the **compliance scan** (see below),
52
72
  then exit.
53
73
  - `status == "PENDING"` → proceed with full initialization.
@@ -89,7 +109,7 @@ On decline: exit with the gap list as a reference for the user to address manual
89
109
 
90
110
  **Clear upgrade marker:** After the compliance scan completes (whether all checks passed or
91
111
  gaps were fixed), run
92
- `{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py project-init-complete --agent <agent-id>`.
112
+ `{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py project-init-complete --session-file <P> --agent <agent-id>`.
93
113
  This removes `pending_init_since` and clears the "Waiting init · Upgrade" status line so the
94
114
  user is no longer prompted on every session. Use the returned `status_context` as the current
95
115
  status source.
@@ -147,7 +167,7 @@ agent must be able to see what was generated and on what evidence.
147
167
  Also ensure `SHORT_MEMORY_TEMPLATE.md` exists in `memory/` as format reference. Never write
148
168
  fake entries.
149
169
  7. **Mark complete** — write the final `init_log` entry, then run
150
- `{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py project-init-complete --agent <agent-id>`.
170
+ `{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py project-init-complete --session-file <P> --agent <agent-id>`.
151
171
  Use the returned `status_context`, then tell the user initialization is done and daily work
152
172
  goes through `{{skill_trigger}}ec-workflow`.
153
173
 
@@ -52,7 +52,8 @@ confirms two critical gates, lite uses the same gates but forces IMPLEMENT -> VE
52
52
  and auto advances legal edges automatically. Lite never enters REVIEW. VERIFICATION remains
53
53
  the code-task fresh-evidence hard gate, and MEMORY keeps the conditional long-memory threshold
54
54
  gate. The active task
55
- pointer lives in `sessions/{ppid}.json`;
55
+ pointer lives in `sessions/{agent}-{session-id}.json` (with an agent-prefixed PPID fallback only
56
+ when a hook payload has no logical session ID);
56
57
  when the task reaches `COMPLETE` or `CLOSED`, the state API clears `current_task` so the
57
58
  session returns to Ready. Each task's stage persists in its `task.json`. Hooks inject the
58
59
  session and task state as breadcrumbs so every reply can render the status line.
@@ -37,23 +37,27 @@ Python runtime files are shared verbatim across platforms (only the JSON wrapper
37
37
  transitions, and task state reads.
38
38
  - `easy_coding_status.py` — renders the Markdown status line and machine breadcrumbs from
39
39
  state API snapshots.
40
- - `session-start.py` — ensures the per-session file exists; performs legacy `state.json`
41
- migration; injects resume / init-required / handoff breadcrumbs. Idempotent.
42
- - `inject-workflow-state.py` — injects the `workflow-state` and `current-task` breadcrumbs so
43
- the status line can render.
40
+ - `session-start.py` — initializes the per-session file on native session-start events and emits
41
+ resume / init-required / handoff breadcrumbs.
42
+ - `inject-workflow-state.py` — idempotently ensures the session and injects the `workflow-state`
43
+ and `current-task` breadcrumbs so the status line can render.
44
44
  - `inject-subagent-context.py` — injects the sub-agent guard before an Agent tool call.
45
45
 
46
46
  Wrapper differences:
47
47
 
48
48
  - **Claude Code**: full event set — `SessionStart`, `UserPromptSubmit`, `PreToolUse(Agent)`.
49
- `session-start.py` also runs on `UserPromptSubmit` before `inject-workflow-state.py`, so
50
- every prompt receives a fresh status context even if the native session event is not surfaced
51
- to the model turn.
52
- - **Codex**: no `SessionStart` and no Agent tool. `session-start.py` and
53
- `inject-workflow-state.py` both hang off `UserPromptSubmit`; `inject-subagent-context.py`
54
- is skipped. Codex hooks also require user-level enablement (`[features] hooks = true`).
55
- - **Qoder**: like Claude Code (has Agent tool + Stop) but uses `UserPromptSubmit` for state
56
- injection. The `.qoder/settings.json` wrapper nests an extra `hooks` array.
57
-
58
- `session-start.py` is designed to be idempotent precisely because Claude/Codex/Qoder can fire it
59
- on `UserPromptSubmit` rather than only a real session-start event repeated calls are safe.
49
+ `session-start.py` owns native session initialization, while `inject-workflow-state.py` is the
50
+ single session writer on each prompt.
51
+ - **Codex**: `session-start.py` runs on `SessionStart`, while
52
+ `inject-workflow-state.py` runs on `UserPromptSubmit`; `inject-subagent-context.py` is
53
+ skipped because Codex has no Agent tool hook. Codex hooks also require user-level enablement
54
+ (`[features] hooks = true`).
55
+ - **Qoder**: has no separate session-start registration, so `inject-workflow-state.py` performs
56
+ idempotent initialization and state injection as the single `UserPromptSubmit` writer. Qoder
57
+ also has Agent tool + Stop hooks, and `.qoder/settings.json` nests an extra `hooks` array.
58
+
59
+ Every session-writing hook resolves the same agent-prefixed logical session key from the hook
60
+ payload, for example `codex-<session-id>.json`. On first use it adopts a legacy `<ppid>.json`
61
+ file when present. A global atomic migration lock ensures only one concurrently starting session
62
+ can claim legacy `state.json`; the winner commits its canonical session before removing the old
63
+ state and releasing the lock.
@@ -263,11 +263,29 @@ Re-output the COMPLETE revised dev-spec.md:
263
263
  3. Overwrite the `plan` record in execution.jsonl with the new strategy.
264
264
  4. For code tasks, update test-strategy.md if test scope changed. For read-only tasks, keep the
265
265
  file absent.
266
- 5. Request ANALYSIS -> IMPLEMENT again and present the standard confirmation/handoff/Other gate.
266
+ 5. Request ANALYSIS -> IMPLEMENT again and present the complete confirmation/handoff/Other gate
267
+ defined below.
268
+
269
+ ## ANALYSIS -> IMPLEMENT choice gate (hard)
270
+
271
+ The same turn that `request-transition` succeeds must invoke the platform's native user-choice
272
+ tool when one is available. The visible branches are:
273
+
274
+ 1. Confirm entering IMPLEMENT (recommended)
275
+ 2. Hand off to another agent
276
+ 3. Other — use the native free-form Other input for revisions or another instruction.
277
+
278
+ If no native choice tool exists, render all three branches as a numbered text fallback. An empty,
279
+ dismissed, timed-out, or unparseable result keeps the task in ANALYSIS with its pending edge and
280
+ may retry the native choice at most once per assistant turn. If that retry also fails, stop the
281
+ current turn and re-present the complete gate on the next user interaction. Never replace the gate
282
+ with only "reply confirm", "confirm execution", or a statement that no valid choice was received,
283
+ and never invoke native choice repeatedly in the same turn. Choosing handoff delegates to
284
+ ec-workflow's existing target-less `handoff-task` flow; do not ask the user to name the next agent.
267
285
 
268
286
  ## End state
269
287
 
270
288
  Read dev-spec.md back from disk and output the COMPLETE content as your reply to the user —
271
- not a summary, not a different format, not a table you invented. Then ask ec-workflow to
272
- record `pending_transition: ANALYSIS -> IMPLEMENT`, present the standard boundary choices,
289
+ not a summary, not a different format, not a table you invented. Then ask ec-workflow to record
290
+ `pending_transition: ANALYSIS -> IMPLEMENT`, immediately present the complete choice gate above,
273
291
  and stop. Never start implementing from this skill.
@@ -18,13 +18,17 @@ recorded comment/doc language.
18
18
 
19
19
  Create one file under `.easy-coding/memory/short/` following the format in
20
20
  `.easy-coding/memory/SHORT_MEMORY_TEMPLATE.md`. File naming convention:
21
- `{NNN}_{YYYYMMDD}_{smart_name}.md`. The entry is immutable after creation.
21
+ `{memory_id}_{YYYYMMDD}_{smart_name}.md`. Generate the id first with
22
+ `{{PYTHON_CMD}} {{platform_config_dir}}/hooks/easy_coding_state.py memory-new-id --session-file <P> --agent <agent-id>`.
23
+ Use the returned `memory_id` unchanged as both the filename prefix and the frontmatter `id`.
24
+ It uses UUIDv7, so agents never scan the directory or calculate a shared numeric sequence.
25
+ Keep the readable `smart_name` suffix. The entry is immutable after creation.
22
26
  Frontmatter (all fields required):
23
27
 
24
28
  ```yaml
25
29
  ---
26
30
  memory_schema: 2
27
- id: SM-{YYYYMMDD}-{NN}
31
+ id: {memory_id returned by memory-new-id, exact}
28
32
  source_task: {current task id, exact}
29
33
  date: {YYYY-MM-DD}
30
34
  task_type: {feature | bugfix | refactor | perf | doc | workflow}
@@ -53,7 +57,8 @@ After the file is successfully written, record the checkpoint immediately:
53
57
  Use the returned `status_context` as authoritative. On resume, if `memory_progress` already
54
58
  shows `short_memory_written:true`, do not create a duplicate entry; continue from Step 2.
55
59
  The state API validates `memory_schema: 2`, requires `source_task` to equal the current task id,
56
- and fingerprints the file. Do not reuse an older task's memory file as this checkpoint.
60
+ requires a UUIDv7 id that exactly matches the filename prefix, and fingerprints the file. Do not
61
+ reuse an older task's memory file as this checkpoint.
57
62
 
58
63
  ## Supermodule memory routing
59
64
 
@@ -144,11 +144,12 @@ it, routing matches, and switching happens again.
144
144
  - **Always-automatic mechanical edges.** After INIT work completes, call `auto-transition` for
145
145
  ANALYSIS. After `memory-complete`, call `auto-transition` for COMPLETE. These two edges never
146
146
  create `pending_transition` in any mode.
147
- - **Native choice first (hard requirement).** When the effective mode requires confirmation,
148
- call `request-transition`. After it succeeds, you MUST
149
- prefer the agent/platform's native user-choice tool whenever one is available. Do not render
150
- a plain-text numbered list on a platform that can present selectable options and a free-form
151
- Other input. Offer exactly these business branches through that native UI:
147
+ - **Native choice rendering is mandatory (hard requirement).** When the effective mode requires
148
+ confirmation, call `request-transition`. After it succeeds, the boundary is not fully presented
149
+ until the user can actually choose every required business branch. When the agent/platform
150
+ exposes a native user-choice tool, you MUST actually invoke it in the same turn; mentioning the
151
+ tool, recommending a reply, or printing only a confirmation sentence is not a substitute. Offer
152
+ exactly these business branches through that native UI:
152
153
  1. Confirm entering/returning to `<target-stage>` (recommended)
153
154
  2. Hand off to another agent
154
155
  3. Other — use the native tool's built-in free-form Other input.
@@ -158,9 +159,22 @@ it, routing matches, and switching happens again.
158
159
  VERIFICATION, cancel that edge, request IMPLEMENT -> VERIFICATION, and immediately confirm it
159
160
  because that selection is explicit confirmation of the alternate target.
160
161
  Plain-text numbered choices are fallback only: use them only when no native user-choice tool
161
- exists. The runtime hook never mutates workflow state from user-prompt text. Native choice
162
- results, numbered fallback replies, and every natural-language reply must be interpreted by
163
- you against the current task and stored target before calling `confirm-transition` explicitly.
162
+ exists. An ordinary gate must list all three branches rather than collapsing to "reply confirm":
163
+ `1. Confirm entering/returning to <target-stage> (recommended)`,
164
+ `2. Hand off to another agent`, `3. Other (describe revisions or another instruction)`.
165
+ The code-task IMPLEMENT completion fallback must preserve its special branch set:
166
+ `1. Enter REVIEW (recommended)`, `2. Skip REVIEW and enter VERIFICATION`,
167
+ `3. Hand off to another agent`, `4. Other (describe revisions or another instruction)`.
168
+ An empty, dismissed, timed-out, or unparseable choice result is not confirmation. Preserve the
169
+ pending edge and re-present the complete native choice UI at most once per assistant turn. If
170
+ that retry is also empty, dismissed, timed out, or unparseable, stop the current turn with the
171
+ pending edge intact and re-present the gate on the next user interaction; never call the native
172
+ choice tool repeatedly in the same turn. If native choice is no longer available, render the
173
+ appropriate complete numbered fallback. Never report "no valid choice" and then show only a
174
+ confirmation instruction. The runtime hook never mutates workflow state from user-prompt text.
175
+ Native choice results, numbered fallback replies, and every natural-language reply must be
176
+ interpreted by you against the current task and stored target before calling
177
+ `confirm-transition` explicitly.
164
178
  On Other feedback, cancel the pending edge before revising work or requesting a different
165
179
  legal target. Never interpret silence, enthusiasm, or topic changes as confirmation.
166
180
  - **State before action.** Every confirmation-required stage advance is a two-step protocol: first
@@ -47,6 +47,16 @@ First run `ec-init`; daily work goes through `ec-workflow`.
47
47
  - Confirmation-required edges use `pending_transition`; automatic edges use the restricted
48
48
  `auto-transition` API. A read-only task creates no test-strategy.md, never enters REVIEW,
49
49
  VERIFICATION, or MEMORY, and writes no task memory.
50
+ - A confirmation-required boundary is not fully presented until the user can choose its complete
51
+ business branches. When a native user-choice tool is available, invoke it in the same turn with
52
+ the complete gate. An ordinary gate offers "confirm entering/returning to the target stage"
53
+ (recommended) and "hand off to another agent", with free-form Other for revisions. The special
54
+ approve-mode code IMPLEMENT gate must instead preserve enter REVIEW, skip to VERIFICATION, and
55
+ handoff, with free-form Other. Only when no native choice tool exists may you show the matching
56
+ complete numbered fallback. Empty, dismissed, timed-out, or unparseable results preserve the
57
+ pending edge and may retry native choice at most once per assistant turn; after a failed retry,
58
+ stop the turn and re-present the gate on the next user interaction. Never degrade to only
59
+ "reply confirm" or repeatedly invoke native choice in the same turn.
50
60
  - When `[easy-coding:no-harness]` is injected, do not emit an Easy Coding status line and ignore
51
61
  only Easy Coding workflow/stage orchestration for this session. Continue honoring every
52
62
  non-Easy-Coding skill, hook, and instruction. Do not clear or mutate the suspended task.
@@ -45,6 +45,16 @@ First run `/ec-init`; daily work goes through `/ec-workflow`.
45
45
  - Confirmation-required edges use `pending_transition`; automatic edges use the restricted
46
46
  `auto-transition` API. A read-only task creates no test-strategy.md, never enters REVIEW,
47
47
  VERIFICATION, or MEMORY, and writes no task memory.
48
+ - A confirmation-required boundary is not fully presented until the user can choose its complete
49
+ business branches. When a native user-choice tool is available, invoke it in the same turn with
50
+ the complete gate. An ordinary gate offers "confirm entering/returning to the target stage"
51
+ (recommended) and "hand off to another agent", with free-form Other for revisions. The special
52
+ approve-mode code IMPLEMENT gate must instead preserve enter REVIEW, skip to VERIFICATION, and
53
+ handoff, with free-form Other. Only when no native choice tool exists may you show the matching
54
+ complete numbered fallback. Empty, dismissed, timed-out, or unparseable results preserve the
55
+ pending edge and may retry native choice at most once per assistant turn; after a failed retry,
56
+ stop the turn and re-present the gate on the next user interaction. Never degrade to only
57
+ "reply confirm" or repeatedly invoke native choice in the same turn.
48
58
  - When `[easy-coding:no-harness]` is injected, do not emit an Easy Coding status line and ignore
49
59
  only Easy Coding workflow/stage orchestration for this session. Continue honoring every
50
60
  non-Easy-Coding skill, hook, and instruction. Do not clear or mutate the suspended task.
@@ -1,21 +1,12 @@
1
1
  {
2
2
  "hooks": {
3
3
  "UserPromptSubmit": [
4
- {
5
- "hooks": [
6
- {
7
- "type": "command",
8
- "command": "{{platform_hook_session_start_command}}",
9
- "timeout": 10
10
- }
11
- ]
12
- },
13
4
  {
14
5
  "hooks": [
15
6
  {
16
7
  "type": "command",
17
8
  "command": "{{platform_hook_inject_workflow_state_command}}",
18
- "timeout": 5
9
+ "timeout": 10
19
10
  }
20
11
  ]
21
12
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  memory_schema: 2
3
- id: SM-YYYYMMDD-001
3
+ id: {memory_id}
4
4
  source_task: MM-DD-task-slug
5
5
  date: YYYY-MM-DD
6
6
  task_type: feature | bugfix | refactor | perf | doc | workflow
@@ -20,14 +20,17 @@ target_long: BUSINESS | TECHNICAL | BOTH | NONE
20
20
  # Short Memory Template
21
21
 
22
22
  > This template defines the format for files under `.easy-coding/memory/short/`.
23
- > File naming convention: `{NNN}_{YYYYMMDD}_{smart_name}.md`
23
+ > File naming convention: `{memory_id}_{YYYYMMDD}_{smart_name}.md`
24
+ > Generate `memory_id` through the state API `memory-new-id` command and use it unchanged as
25
+ > both the filename prefix and this frontmatter `id`. The UUIDv7 id is safe for concurrent agents.
26
+ > Keep `smart_name` as the readable summary suffix.
24
27
  > `source_task` must exactly match the current workflow task id from `task.json`.
25
28
  > Short memories are immutable after creation — they serve as a sliding window of recent
26
29
  > details and a buffer for long-term distillation candidates.
27
30
  > When short memories reach the threshold (default 10), the newest 5 are kept as recent
28
31
  > context; older entries are distillation candidates for long-term memory.
29
- > Sorting: by frontmatter `date` ascending; if date is missing or tied, by filename prefix
30
- > number ascending; then by filename ascending.
32
+ > Sorting: by frontmatter `date` ascending, then by frontmatter `id`, then by filename. Legacy
33
+ > `SM-YYYYMMDD-NNN` ids sort before UUIDv7 ids on the same date for upgrade compatibility.
31
34
 
32
35
  ## Task Summary
33
36
 
@@ -29,7 +29,7 @@
29
29
  - **核心类 / 页面 / 接口**:[[EC_TODO:核心类 / 页面 / 接口]]
30
30
  - **数据库变更**:[[EC_TODO:有/无]]
31
31
  - **接口变更**:[[EC_TODO:有/无]]
32
- - **关联历史任务**:[[EC_TODO:相关短期记忆序号;无则“无”]]
32
+ - **关联历史任务**:[[EC_TODO:相关短期记忆 ID;无则“无”]]
33
33
 
34
34
  ### 改动范围
35
35
  > 只列真实项目源码/配置文件的改动。禁止把 `.easy-coding/` 下的 harness 产物(dev-spec / execution.jsonl / test-strategy / 记忆 / 报告等)当作改动对象。本表为空仅允许用于"用户明确要求的无代码交付形态";代码类任务(重构/修复/功能)若此表为空,即为自我降级。