@tacuchi/agent-workflow-cli 20.22.0 → 20.23.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 (109) hide show
  1. package/dist/adapters/git-cli.js +42 -0
  2. package/dist/adapters/git-cli.js.map +1 -1
  3. package/dist/application/artifacts-service.js +5 -5
  4. package/dist/application/artifacts-service.js.map +1 -1
  5. package/dist/application/checkpoint-service.js +60 -55
  6. package/dist/application/checkpoint-service.js.map +1 -1
  7. package/dist/application/checkpoint-write-service.js +61 -66
  8. package/dist/application/checkpoint-write-service.js.map +1 -1
  9. package/dist/application/decisiones-service.js +5 -5
  10. package/dist/application/decisiones-service.js.map +1 -1
  11. package/dist/application/export-service.js +250 -0
  12. package/dist/application/export-service.js.map +1 -0
  13. package/dist/application/fix-git-service.js +244 -0
  14. package/dist/application/fix-git-service.js.map +1 -0
  15. package/dist/application/history-update-service.js +35 -24
  16. package/dist/application/history-update-service.js.map +1 -1
  17. package/dist/application/lifecycle-target.js +39 -0
  18. package/dist/application/lifecycle-target.js.map +1 -0
  19. package/dist/application/parsers/spec-relation.js +80 -0
  20. package/dist/application/parsers/spec-relation.js.map +1 -0
  21. package/dist/application/paths-service.js +8 -0
  22. package/dist/application/paths-service.js.map +1 -1
  23. package/dist/application/persist-service.js +285 -0
  24. package/dist/application/persist-service.js.map +1 -0
  25. package/dist/application/release-data/artifacts.js +17 -21
  26. package/dist/application/release-data/artifacts.js.map +1 -1
  27. package/dist/application/resume-service.js +184 -0
  28. package/dist/application/resume-service.js.map +1 -0
  29. package/dist/application/semantic-operation/protocol.js +247 -0
  30. package/dist/application/semantic-operation/protocol.js.map +1 -0
  31. package/dist/application/semantic-operation/publish.js +80 -0
  32. package/dist/application/semantic-operation/publish.js.map +1 -0
  33. package/dist/application/session-binding-service.js +125 -0
  34. package/dist/application/session-binding-service.js.map +1 -0
  35. package/dist/application/session-close-service.js +60 -39
  36. package/dist/application/session-close-service.js.map +1 -1
  37. package/dist/application/session-create-service.js +45 -19
  38. package/dist/application/session-create-service.js.map +1 -1
  39. package/dist/application/session-resolver.js +180 -44
  40. package/dist/application/session-resolver.js.map +1 -1
  41. package/dist/application/session-resume-service.js +39 -9
  42. package/dist/application/session-resume-service.js.map +1 -1
  43. package/dist/application/sessions-service.js +0 -2
  44. package/dist/application/sessions-service.js.map +1 -1
  45. package/dist/application/status-service.js +24 -388
  46. package/dist/application/status-service.js.map +1 -1
  47. package/dist/application/tasks-service.js +5 -5
  48. package/dist/application/tasks-service.js.map +1 -1
  49. package/dist/application/workline-index-service.js +510 -0
  50. package/dist/application/workline-index-service.js.map +1 -0
  51. package/dist/cli/commands/checkpoint-read.js +10 -6
  52. package/dist/cli/commands/checkpoint-read.js.map +1 -1
  53. package/dist/cli/commands/checkpoint-write.js +38 -11
  54. package/dist/cli/commands/checkpoint-write.js.map +1 -1
  55. package/dist/cli/commands/export.js +117 -0
  56. package/dist/cli/commands/export.js.map +1 -0
  57. package/dist/cli/commands/fix-git.js +109 -0
  58. package/dist/cli/commands/fix-git.js.map +1 -0
  59. package/dist/cli/commands/generate-launch.js +35 -3
  60. package/dist/cli/commands/generate-launch.js.map +1 -1
  61. package/dist/cli/commands/history-update.js +1 -1
  62. package/dist/cli/commands/history-update.js.map +1 -1
  63. package/dist/cli/commands/index.js +11 -0
  64. package/dist/cli/commands/index.js.map +1 -1
  65. package/dist/cli/commands/persist.js +67 -0
  66. package/dist/cli/commands/persist.js.map +1 -0
  67. package/dist/cli/commands/resume-summary.js +14 -3
  68. package/dist/cli/commands/resume-summary.js.map +1 -1
  69. package/dist/cli/commands/resume.js +73 -0
  70. package/dist/cli/commands/resume.js.map +1 -0
  71. package/dist/cli/commands/session-artifacts.js +12 -11
  72. package/dist/cli/commands/session-artifacts.js.map +1 -1
  73. package/dist/cli/commands/session-close.js +8 -7
  74. package/dist/cli/commands/session-close.js.map +1 -1
  75. package/dist/cli/commands/session-create.js +5 -1
  76. package/dist/cli/commands/session-create.js.map +1 -1
  77. package/dist/cli/commands/session-resume.js +16 -10
  78. package/dist/cli/commands/session-resume.js.map +1 -1
  79. package/dist/cli/commands/status.js +66 -2
  80. package/dist/cli/commands/status.js.map +1 -1
  81. package/dist/cli/commands/workspace-init.js +21 -2
  82. package/dist/cli/commands/workspace-init.js.map +1 -1
  83. package/dist/cli/context-id.js +133 -0
  84. package/dist/cli/context-id.js.map +1 -0
  85. package/dist/cli/help-groups.js +16 -1
  86. package/dist/cli/help-groups.js.map +1 -1
  87. package/dist/cli/main.js +44 -16
  88. package/dist/cli/main.js.map +1 -1
  89. package/dist/cli/output-mode.js +41 -0
  90. package/dist/cli/output-mode.js.map +1 -0
  91. package/dist/cli/parser.js +6 -0
  92. package/dist/cli/parser.js.map +1 -1
  93. package/dist/cli/registry.js.map +1 -1
  94. package/dist/cli/render.js +53 -0
  95. package/dist/cli/render.js.map +1 -1
  96. package/package.json +1 -1
  97. package/skills/w/commands/export-diagrams.md +19 -10
  98. package/skills/w/commands/export-manuals.md +20 -10
  99. package/skills/w/commands/export-reports.md +20 -11
  100. package/skills/w/commands/export-scripts.md +20 -10
  101. package/skills/w/commands/fix-git.md +31 -12
  102. package/skills/w/commands/generate-launch.md +1 -1
  103. package/skills/w/commands/persist.md +33 -68
  104. package/skills/w/commands/resume.md +25 -46
  105. package/skills/w/commands/status.md +12 -48
  106. package/skills/w/commands/workspace-init.md +3 -3
  107. package/skills/w/hooks/README.md +21 -2
  108. package/skills/w/hooks/hooks.template.json +2 -2
  109. package/skills/w/roles/git/ROLE.md +7 -8
@@ -1,101 +1,66 @@
1
1
  ---
2
- description: Use when work already produced in this conversation (analysis, conclusions, a plan) should be saved into docs/ — classifies its shape and routes it. analysis → docs/research/ · requirement → spec draft (docs/specs) · plan → plan adoption (docs/plans). Transversal (no flow, no loop, no session); records ## Origin + attribution (host · model · date); anti-duplicate aware (update vs sibling perspective). The host→docs/ counterpart of export-*.
2
+ description: Use when work already produced in this conversation (analysis, conclusions, a plan) should be saved into docs/ — classifies its shape and routes it. analysis → docs/research/ · requirement → spec draft (docs/specs) · plan → plan adoption (docs/plans). Backed by `aw persist`, which owns the inventory, the anti-duplicate check, the numbering, the destination and the write. Transversal (no flow, no loop, no session); records ## Origin + attribution.
3
3
  argument-hint: [what to persist — empty = the conversation's latest finished deliverable]
4
4
  allowed-tools:
5
5
  [
6
6
  "Bash",
7
7
  "Read",
8
- "Write",
9
- "Edit",
10
8
  ]
11
9
  ---
12
10
 
13
11
  # persist — persist in-conversation work into `docs/`
14
12
 
15
- Captures **work already produced in this conversation** — with or without host-native features (a `/goal` run, plan mode, plain chat analysis) — and persists it into `docs/`, classified by shape. It is the explicit form of *direct no-flow authoring* (`../SKILL.md` § *Operating context*, row 3) and the doctrinal entry for **host as producer** (`../loops/CHASSIS.md` § *Adopted context*).
13
+ Captures **work already produced in this conversation** — with or without host-native features (a `/goal` run, plan mode, plain chat analysis) — and persists it into `docs/`, classified by shape. The explicit form of *direct no-flow authoring* (`../SKILL.md` § *Operating context*, row 3) and the doctrinal entry for **host as producer** (`../loops/CHASSIS.md` § *Adopted context*). The host→`docs/` counterpart of `export-*`.
16
14
 
17
15
  > **Hard floor — applies even if you read nothing beyond this file:**
18
16
  >
19
17
  > 1. **Adopt, don't re-derive** — single pass, **NO RESEARCH**: transcribe/organize what the conversation already established. New investigation is flow work (`spec-refine`, `quick`), never this command's.
20
- > 2. **Confirm before writing** — classification and destination go through **structured-choice** (recommendation first). Never write `docs/` silently.
21
- > 3. **Numbering via `aw next-number docs/<category>`** (it creates the folder when missing) never invent numbers. **Never creates sessions** (sessions are loop-created only).
22
- > 4. **Language** — headings in English (parse contract); content in the **user's language**.
18
+ > 2. **You classify and write; the CLI decides everything else** — inventory, anti-duplicate, numbering, destination, authorization and the write itself belong to `aw persist`. Never write into `docs/` with a file tool here; `Write`/`Edit` are deliberately not in `allowed-tools`.
19
+ > 3. **Never invent the number** the `NNN` you put in the path is consultative; `apply` reassigns it inside the lock. Do not renumber it.
20
+ > 4. **Confirm before writing** — classification and destination go through **structured-choice**; `apply` refuses without the digest `validate` returned. **Never creates sessions** (sessions are loop-created only).
21
+ > 5. **Language** — headings in English (parse contract); content in the **user's language**.
23
22
 
24
23
  ## Input
25
24
 
26
- `$ARGUMENTS` names what to persist (or is empty → the conversation's most recent finished deliverable). The **source is the conversation itself**: what was analyzed, concluded, designed or planned up to this point. If nothing persistable exists yet, say so and stop — do not manufacture content.
25
+ `$ARGUMENTS` names what to persist (or is empty → the conversation's most recent finished deliverable). The **source is the conversation itself**. If nothing persistable exists yet, say so and stop — do not manufacture content.
27
26
 
28
- ## Classification → routing
29
-
30
- Classify the content by **shape**, recommend the route, confirm via structured-choice:
31
-
32
- | Shape | Signals | Route |
33
- |---|---|---|
34
- | **Analysis / conclusions / design notes** | findings, comparisons, diagnoses, adjudications, recommendations | `docs/research/NNN-research-<slug>.md` (schema below) |
35
- | **Requirement** | describes a *wish*: what should exist/change, acceptance criteria derivable | **spec draft** via the [`spec-new`](spec-new.md) procedure (same schema, same NO RESEARCH), `## Origin` = "adopted from host conversation" → offer `/w:spec-refine` |
36
- | **Plan** | already answers the *how*: phases/tasks/solution — e.g. the host plan-mode output | **plan adoption** via [`plan-new`](plan-new.md) § *Input resolution* mode 4 (`docs/plans/PPP-plan-<slug>.md`) → offer `/w:plan-refine` / `/w:plan-exec` |
37
- | Mixed / ambiguous | e.g. analysis that ends in a requirement | structured-choice between the candidate routes (split is a valid option: research doc + spec draft referencing it) |
38
-
39
- Requires a **workspace** (`docs/` is the managed surface). Without one → degrade: propose `/w:workspace-init` or ask for an explicit destination path.
40
-
41
- ## `docs/research/` — the analysis home (owned by this command)
42
-
43
- `docs/research` hosts standalone analyses: neither spec nor plan, but worth keeping. Written by this command (or by direct no-flow authoring following this same schema). Belongs to **no flow**; `export-*` never writes it; loops never read it implicitly (a flow uses it by **reference** — e.g. cited in a spec's `## Origin` or a quick prompt).
44
-
45
- ```markdown
46
- # Research NNN — <slug>
47
-
48
- ## Origin
49
- adopted from host conversation — <host> · <model> · <YYYY-MM-DD>
50
- (what prompted the analysis: goal, prior doc, question)
27
+ ## Run
51
28
 
52
- ## Objective
53
- The question/situation the analysis addresses. In the user's language.
29
+ 1. `aw persist prepare --format human` (`--detail` prints the full response contract). Returns the inventory of the three categories, the consultative numbering, the allowed destinations, the limits and an `input_digest`.
30
+ 2. **Classify and write.** Compose one JSON answer:
31
+ - `version`, `operation`, `input_digest` copied **verbatim** from the request;
32
+ - `state`: `proposed`, or `ambiguous` when the inventory already holds this work (explain in `reason` — the CLI turns that into a question, never a write);
33
+ - `decisions`: `{ category, slug, mode }`, plus `target` + `target_digest` when `mode` is `update`;
34
+ - `artifacts`: exactly one `{ path, content }`.
35
+ 3. `echo '<json>' | aw persist validate --format human` → preview + `approval_digest`.
36
+ 4. **Confirm classification and destination** with the user via structured-choice, showing that preview.
37
+ 5. `echo '<json>' | aw persist apply --approval <digest> --format human`.
54
38
 
55
- ## Analysis
56
- The analysis, transcribed/organized (not re-derived).
39
+ Every rejection names its cause and one valid next action; nothing was written. Fix the answer and repeat from step 3.
57
40
 
58
- ## Conclusions
59
- The settled conclusions — actionable, falsifiable where possible.
60
-
61
- ## Perspectives (opt. — multi-agent)
62
- ### <host · model · YYYY-MM-DD>
63
- An additional agent's view on the same objective (see below).
64
-
65
- ## Sources (opt.)
66
- Docs / repos / prior research docs referenced (for a synthesis: the N crossed docs).
67
-
68
- ## Open questions (opt.)
69
- ```
70
-
71
- ## Anti-duplicate → update vs sibling perspective
72
-
73
- Before writing, scan `docs/research/*-research-*.md` for a doc whose `## Origin`/`## Objective` matches this objective. If one exists, **never** silently create a second: structured-choice —
74
-
75
- - **`Actualizar`** *(recommended when it is the same line of thought)* — correct/extend the existing doc in place (confirmation to overwrite).
76
- - **`Agregar perspectiva`** — append a `### <host · model · date>` subsection under `## Perspectives`: same objective, **different agent's view** (this is intentional and legitimate — the multi-host pattern below).
77
- - **`Documento nuevo`** — only if the objective genuinely differs.
41
+ ## Classification → routing
78
42
 
79
- ## Multi-host cross-analysis (the docs-mediated pattern)
43
+ | Shape | Signals | Category → destination |
44
+ |---|---|---|
45
+ | **Analysis / conclusions / design notes** | findings, comparisons, diagnoses, adjudications, recommendations | `research` → `docs/research/NNN-research-<slug>.md` |
46
+ | **Requirement** | describes a *wish*: what should exist/change, acceptance criteria derivable | `spec` → `docs/specs/NNN-spec-<slug>.md`, born `status: draft`, `## Origin` = "adopted from host conversation" → offer `/w:spec-refine` |
47
+ | **Plan** | already answers the *how*: phases/tasks/solution — e.g. the host plan-mode output | `plan` → `docs/plans/NNN-plan-<slug>.md` (adoption, [`plan-new`](plan-new.md) § *Input resolution* mode 4) → offer `/w:plan-refine` / `/w:plan-exec` |
48
+ | Mixed / ambiguous | e.g. analysis that ends in a requirement | one `persist` per document, each confirmed; a research doc plus a spec draft that cites it is a valid split |
80
49
 
81
- `docs/research` is git-shareable — unlike sessions (gitignored, machine-local, loop-owned). That makes it the exchange surface for **N agents analyzing the same situation**:
50
+ Requires a **workspace** (`docs/` is the managed surface). Without one degrade: propose `/w:workspace-init`.
82
51
 
83
- 1. **Each host** analyzes in-conversation, then runs `/w:persist` → first agent creates the research doc; the rest **add perspectives** (or sibling docs), always attributed (host · model · date).
84
- 2. **The final cross**: the user picks the strongest host; its input is the N research docs/perspectives (referenced explicitly in the prompt or via this command's argument). The synthesis persists as a **new research doc** whose `## Origin` states "synthesis" and whose `## Sources` lists every doc/perspective crossed — attribution lets it weigh who concluded what.
85
- 3. Sessions stay **out** of the exchange path — no concurrent-session doctrine is needed; hosts meet only in `docs/`.
52
+ ## `docs/research/` the analysis home (owned by this command)
86
53
 
87
- ## What this command is NOT
54
+ `docs/research` hosts standalone analyses: neither spec nor plan, but worth keeping. Belongs to **no flow**; `export-*` never writes it; loops never read it implicitly (a flow uses it by **reference** — cited in a spec's `## Origin` or a quick prompt). It is git-shareable, unlike sessions (gitignored, machine-local, loop-owned), which makes it the exchange surface for **N agents analyzing the same situation**.
88
55
 
89
- - **Not export-*** it never reads sessions; `export-*` remains the only session→`docs/` path.
90
- - **Not a flow** — no loop, no session, no `CHECKPOINT`; single pass.
91
- - **Not research** — it investigates nothing (NO RESEARCH); it persists what already exists.
56
+ > **Anti-duplicate is a decision, not an accident.** The inventory carries each existing document's summary and digest. Same work already there → `mode: "update"` (proving you saw the current bytes via `target_digest`) or `state: "ambiguous"` so the user chooses between updating and writing a sibling perspective. A second near-identical document is never created silently.
92
57
 
93
58
  ## Plan mode
94
59
 
95
- Classifies the content, resolves `NNN`/destination (`aw next-number --dry-run`) and describes the doc it would write (or the update/perspective it would append) without writing anything.
60
+ Describe the classification, the destination and the document it would write. Running `prepare` is fine (read-only); never `apply`.
96
61
 
97
62
  ## Resources
98
63
 
99
- - Adopted-context doctrine: `../loops/CHASSIS.md` § *Adopted context* · `../SKILL.md` § *Host as producer*
100
- - Spec-draft procedure: [`spec-new.md`](spec-new.md) · Plan adoption: [`plan-new.md`](plan-new.md) § *Input resolution* (mode 4)
101
- - Session→docs counterpart: [`../exports/README.md`](../exports/README.md)
64
+ - CLI: `aw persist prepare | validate | apply` (service `persist-service` over `semantic-operation/`)
65
+ - Siblings: the four `export-*` commands (session `docs/`), same handshake
66
+ - Design reference: `docs/referencias/workflow-skills/persist.md`
@@ -1,6 +1,6 @@
1
1
  ---
2
- description: Use when the user asks to resume or pick up pending work — a half-done session, a spec to refine, a plan mid-execution, or work with no Workline flow at all. Composes /w:status and proposes how to continue via structured-choice routed to the right command; an artifact argument (spec, plan or session) skips the survey and gets its exact re-entry route. Transversal (not a flow), read-only; never touches docs/ or .workflow/. Backed by aw status + aw resume-summary.
3
- argument-hint: "[docs/specs/… | docs/plans/… | session NNN]"
2
+ description: Use when the user asks to resume or pick up pending work — a half-done session, a spec to refine, a plan mid-execution. Backed by `aw resume`, which derives the priority, the progress and the exact re-entry command from the Workline index. An artifact argument (spec, plan or session) skips the survey. Transversal (not a flow), read-only; never touches docs/ or .workflow/.
3
+ argument-hint: "[docs/specs/… | docs/plans/… | NNN | --code <session>]"
4
4
  allowed-tools:
5
5
  [
6
6
  "Bash",
@@ -10,65 +10,44 @@ allowed-tools:
10
10
 
11
11
  # resume — pick up pending work (transversal)
12
12
 
13
- Summarizes what is pending in the workspace and proposes how to continue. Single-pass, **read-only**: no loop, no session, writes nothing in `docs/` or `.workflow/`. **Transversal** command (belongs to no SPEC/PLAN/QUICK flow). The **actionable sibling of `/w:status`**: it composes the `/w:status` summary and adds a proposal layer. With an **argument** (a spec, plan or session) it skips the survey and proposes the exact re-entry route for that artifact (§ *Directed resume*). User-facing output in the user's language.
13
+ Single-pass, **read-only**: no loop, no session, writes nothing in `docs/` or `.workflow/`. **Transversal** command (belongs to no SPEC/PLAN/QUICK flow). The actionable sibling of `/w:status`: same index, but it answers *what to pick up* instead of *what exists*.
14
14
 
15
- > **Not `aw session-resume` / `aw resume-summary` / `create_or_resume`.** Those are internal session mechanics (reopen a session, the PostCompact payload, loop resume). `/w:resume` is the **user-facing** command that *summarizes + proposes*; it never runs the pending work — it routes to the command that does.
15
+ > **Not `aw session-resume` / `aw resume-summary`.** Those are internal session mechanics (reopen a session; the PostCompact payload). `aw resume` is the user-facing command.
16
16
 
17
17
  > **Hard floor — applies even if you read nothing beyond this file:**
18
18
  >
19
- > 1. **Read-only** — never execute the pending work and never write `docs/` or `.workflow/`, **with or without an argument**. Routing means handing off to the target command; the user drives it.
20
- > 2. **Summary always, question only when pending** without an argument, show the prioritized summary every time and ask **only** when there is at least one pending item; with an argument, the directed route *Directed resume*) replaces the survey.
21
- > 3. **Ask via structured-choice** the proposal is a structured-choice with the top ≤3 concrete options, recommendation first. Never route silently.
22
- > 4. **Language** — headings in English (parse contract); user-facing output in the **user's language**.
23
-
24
- ## Directed resume (optional argument)
25
-
26
- `$ARGUMENTS` may name an artifact: a spec (`docs/specs/NNN-spec-<slug>.md`), a plan (`docs/plans/PPP-plan-<slug>.md`) or a session (`NNN` code or `NNN-<slug>-<flow>` folder). Empty → the survey flow below (`## Run`). With an argument:
27
-
28
- 1. **Derive the slug** from the artifact name (session code `NNN` → resolve the folder via `aw sessions --state all`).
29
- 2. **Locate the candidate sessions**: `aw sessions --state all` (and `aw resume-summary --include-recent-closed` for checkpoint detail) filtered by that slug.
30
- 3. **Confirm by `## Origin`**: read the candidates' `SESSION.md` — the `## Origin` names the spec/plan the session came from; it, not the slug match, decides the association.
31
- 4. **Propose the exact route** via structured-choice, per the `## Routing` table with the artifact's path filled in (`Retomar` recommended, `Descartar`/`Cerrar` secondary). No candidate session and no clear stage → say so and fall back to the survey flow.
32
-
33
- Same hard floor: this mode **proposes** the route — it never starts the target command itself.
19
+ > 1. **Read-only** — never execute the proposed route, with or without an argument. The CLI hands back a command string; the user drives it.
20
+ > 2. **Never re-decide** — priority, ties, the spec→plan relation and the exact command come from the CLI. Do not re-sort by date, do not associate a session to a plan by slug, do not pick a winner the CLI left tied.
21
+ > 3. **Ask via structured-choice** when the CLI returns candidates, never otherwise.
22
+ > 4. **Language** — user-facing output in the **user's language**.
34
23
 
35
24
  ## Run
36
25
 
37
- 1. **Workline level — compose `/w:status`.** Read-and-follow [`status.md`](status.md) to produce the prioritized summary (it already renders `aw status` and, when available, the host-context section). Do **not** re-implement the summary. For deeper session detail, `aw resume-summary [--include-recent-closed]` gives the primary session's CHECKPOINT state, and `aw session-resume --code <NNN>` the full checkpoint of any other active or closed session.
38
- 2. **Interpret the stage marks.** Map each signal to its stage: the spec's `status` (`draft`/`refining` = SPEC work still open · `ready-for-plan` = it can go to PLAN) + `open_questions`; plan progress on **all three axes** — checkboxes (`tasks_done` / `tasks_total`), validated phases (`phases_validated` / `phases_total`) and closure (`plan_state`, with `final_validation_pending` and `blocked_phases[]`); session `checkpoint_present`. A `status` that is absent, empty or unknown reads `draft`: that work stays in SPEC and never routes to PLAN on an unreadable mark. Associate a session to its plan or spec by **slug** — there is no linkage field in the `aw status` output, so infer it from `folder` / `slug`; when precision matters, confirm by the session's `## Origin` (§ *Directed resume*).
39
- 3. **Build the prioritized pending list** — fixed order: **session with CHECKPOINT > plan half-done > spec not ready > host context**.
40
- 4. **Host level (second source).** If the workline level does not explain the pending work (or no Workline flow was used), rely on the host-context already surfaced by `/w:status`; escalate it to a proposal and, only if needed, use the host-memory *deep* tier or ask the user (universal fallback: git / `docs/` signals + a question). See [`../harness/HARNESS.md`](../harness/HARNESS.md) § *host-memory*.
41
- 5. **Propose (only when ≥1 pending).** One structured-choice with the top ≤3 options by the priority order; each option **routes** to its command (table below). Every proposal carries `Retomar` (recommended) and `Descartar` / `Cerrar` (secondary).
42
- 6. **Nothing pending.** Show the `/w:status` summary and state clearly that there is nothing pending **do not ask**.
43
-
44
- ## Routing (stage command)
45
-
46
- Priority: **session+CHECKPOINT > plan half-done > spec not ready > host context**.
47
-
48
- > **Every box ticked is not a finished plan.** A plan with `phases_validated` below `phases_total` still has functional state to reach — work implemented, not validated — so it counts as half-done and routes to `/w:plan-exec`, which re-enters at the first phase that is not `validada`. A phase left `bloqueada` routes the same way: `/w:plan-exec` re-enters **through it** to run the validation still pending, and the plan stays open until that phase reads `validada`. A plan with `phases_total: 0` is a legacy plan (no phase marks) and is judged by its checkboxes alone.
26
+ 1. Run `aw resume --format human`, forwarding the argument when there is one:
27
+ - a doc path or number pass it as the positional (`aw resume docs/plans/009-plan-x.md`);
28
+ - a session `aw resume --code <NNN | folder>`;
29
+ - nothing no argument, and the CLI walks the pipeline.
30
+ 2. **Relay the output verbatim.** It already carries the objective, the progress or checkpoint, the next pending step or blocker, and the exact command.
31
+ 3. **When the CLI returns candidates**, present them as a structured-choice, one option per candidate, in the order given the CLI declares a tie precisely because there is no correct automatic winner. Add the `flow` control. Never break the tie yourself.
32
+ 4. **When it returns nothing pending**, say so and stop. Do not ask.
33
+ 5. **Host context (optional).** If nothing is pending at the Workline level and the host exposes cheap host-memory ([`../harness/HARNESS.md`](../harness/HARNESS.md) § *host-memory*), you may add a short note about recent focus. Never expensive, never blocking.
49
34
 
50
- > **`plan_state` decides whether a plan is resumable at all.** Only `done` is finished; everything else routes back to `/w:plan-exec` with a different re-entry point. `final_validation_pending: true` means the phases are green but the final validation never ran — the plan re-enters **at that validation**, not at a phase. `inconsistent` means the document contradicts itself (`done` declared over open work, or an unreadable value): the re-entry is **repairing the state first**, and the proposal says so instead of pretending there is work to implement.
35
+ ## What the CLI decides (do not re-derive)
51
36
 
52
- | Pending detected | `Retomar` (recommended) | Secondary |
53
- |---|---|---|
54
- | spec not ready (`draft` / `refining`, or a `status` absent or unreadable) | `/w:spec-refine` | `Descartar` |
55
- | spec `ready-for-plan`, no plan | `/w:plan-new` | `Descartar` |
56
- | plan `open` — open checkboxes **or** phases not `validada` | `/w:plan-exec` | `Cerrar` |
57
- | plan `open` with `final_validation_pending` — everything validated, no closure | `/w:plan-exec`, from the final validation | `Cerrar` |
58
- | plan `inconsistent` — `done` over open work, or an unreadable value | `/w:plan-exec`, repairing the state first | `Cerrar` |
59
- | plan `done` | — not resumed automatically | — |
60
- | active session with CHECKPOINT | continue / reopen (`aw session-resume --reopen`) | `Cerrar` |
61
- | host context only (no workline) | best next step for what was found | `Descartar` |
37
+ - **Priority**: spec sin refinar → spec `ready-for-plan` sin plan plan incompleto → checkpoint no asociado. Within plans, one already started outranks an untouched one.
38
+ - **Ties**: same priority and same progress → candidates. Date and age never break a tie.
39
+ - **The spec→plan relation**: proven by the plan's `Derived from` header, an explicit spec path in its `## Origin`, or an unambiguous `Spec NNN` there never by slug. A plan whose provenance is unproven leaves its spec visible as still unplanned.
40
+ - **The route**: `/w:spec-refine`, `/w:plan-new`, `/w:plan-exec`, or `aw session-resume --reopen`, with the path already filled in.
62
41
 
63
- Reuses the continuity rule of [`../SKILL.md`](../SKILL.md) § *Operating context* it synthesizes the route from the `/w:status` summary + that rule; it does not re-implement it.
42
+ > A plan is not finished because its boxes are ticked. `aw resume` re-enters at the first phase that is not `validada`, reports a `bloqueada` phase with its declared reason, and, when everything is green but the plan never closed, says the final validation is what remains. A plan that declares `done` over open work comes back as inconsistent — repair before implementing.
64
43
 
65
44
  ## Plan mode
66
45
 
67
- Read-only already: compose `/w:status`, describe the prioritized summary and the proposal it would offer (top ≤3 routed options; with an argument, the exact route it would propose), without asking or writing.
46
+ Read-only already: run `aw resume --format human` and describe the proposal (and the choice it would offer), without asking or writing.
68
47
 
69
48
  ## Resources
70
49
 
71
- - Composes: [`status.md`](status.md) (the summary) · Capability: `host-memory` ([`../harness/HARNESS.md`](../harness/HARNESS.md))
72
- - CLI: `aw status` · `aw resume-summary [--include-recent-closed]` · `aw session-resume --code <NNN> [--reopen]`
50
+ - CLI: `aw resume` (service `resume-service` over `workline-index-service`) · sibling `aw status`
51
+ - Session mechanics: `aw session-resume --code <NNN> [--reopen]` · `aw resume-summary`
73
52
  - Continuity rule: [`../SKILL.md`](../SKILL.md) § *Operating context*
74
53
  - Design reference: `docs/referencias/workflow-skills/resume.md`
@@ -1,6 +1,6 @@
1
1
  ---
2
- description: Use when the user asks "what's the state", "what got done", or "where are we". Read-only workspace dashboard — what got done / what is missing / what was discarded, with dates humanized in the user's language, optionally enriched with host context when the host exposes cheap memory. Backed by `aw status`. Transversal command (not a flow); writes nothing.
3
- argument-hint: (no arguments)
2
+ description: Use when the user asks "what's the state", "what got done", or "where are we". Read-only workspace dashboard — the pending pipeline by default, the full history under detail optionally enriched with host context when the host exposes cheap memory. Backed by `aw status`. Transversal command (not a flow); writes nothing.
3
+ argument-hint: (no arguments — pass `detalle` for the full inventory)
4
4
  allowed-tools:
5
5
  [
6
6
  "Bash",
@@ -10,63 +10,27 @@ allowed-tools:
10
10
 
11
11
  # status — workspace state (read-only)
12
12
 
13
- Shows, simple and direct, the workspace state grouped as **Done / Missing / Discarded**. Single-pass, read-only: no loop, no sessions, writes nothing in `docs/` or `.workflow/`. **Transversal** command (belongs to no flow). When the host exposes cheap memory it *opportunistically* adds a host-context section — additive, never blocking, never asked.
13
+ Single-pass, read-only: no loop, no sessions, writes nothing in `docs/` or `.workflow/`. **Transversal** command (belongs to no flow).
14
14
 
15
15
  ## Run
16
16
 
17
- 1. Run `aw status` (returns JSON; backed by `status-service`).
18
- 2. Render a readable summary from the JSON do **not** show the raw JSON. Use the `relative` field verbatim (it comes pre-humanized in the user's language Spanish). Head it with `workspace.name`.
19
- 3. Group into three blocks (the dashboard is user-facing render it in the user's language; the canonical Spanish labels below):
20
- - `▸ HECHO` — specs whose `status` is `ready-for-plan` (the JSON keeps `refined: true` as its boolean mirror); plans whose `plan_state` is `done`, with their progress (`tasks_done`/`tasks_total`, `progress_pct`) **and** their validated phases (`phases_validated`/`phases_total`); `closed` sessions.
21
- - `▸ FALTA` — `active` sessions; plans whose `plan_state` is `open` (pending tasks `tasks_total − tasks_done`, phases still to validate `phases_total − phases_validated`, or a final validation that never ran); plans whose `plan_state` is `inconsistent`, **naming the contradiction**; specs whose `status` is `draft` or `refining`; specs with `open_questions > 0`.
22
- - `▸ DESCARTÓ` — every item in `discarded[]` (`kind: deferred` = deferred in BACKLOG; `kind: excluded` = excluded in CHECKPOINT), with its `text`.
23
- 4. Every line ends with its relative date after ` · ` (e.g. `· ayer en la mañana`). An empty section shows `— (nada)`. Never invent data not present in the JSON.
24
- 5. **Say what blocks a phase.** Every entry of `blocked_phases[]` is rendered with its `number`, its `name` and its `blocker` — `• F3 — Persistencia real — bloqueada: falta aplicar la migración`. A `blocker: null` is a legacy block that stated no reason: render it as `bloqueada` with `motivo no declarado`, never a guess.
25
- 6. If `workspace.initialized` is `false` and everything is empty → say the folder is not an agent-workflow workspace (no `.workflow/`) and suggest `/w:workspace-init`.
26
- 7. **Host context (opportunistic, read-only).** After the dashboard, if the host exposes *cheap* host-memory (see [`../harness/HARNESS.md`](../harness/HARNESS.md) § *host-memory* — e.g. the auto-memory `MEMORY.md` on Claude Code), append a `▸ CONTEXTO DEL HOST` section with a few signals of recent focus relevant to this workspace. If there is no cheap host memory, **omit the section silently**. Never run an expensive transcript scan here and **never ask** — this is a read-only dashboard; the enrichment is additive and must not slow the default output.
17
+ 1. Run `aw status --format human` add `--detail` when the user asked for the full inventory ("detalle", "todo", "historial").
18
+ 2. **Relay its output verbatim.** The CLI already selects, filters, groups and humanizes the dates; re-rendering it here is what made the two drift apart. Do not paraphrase it, do not re-sort it, do not add or drop a line.
19
+ 3. **Host context (opportunistic, read-only).** After the dashboard, if the host exposes *cheap* host-memory (see [`../harness/HARNESS.md`](../harness/HARNESS.md) § *host-memory* — e.g. the auto-memory `MEMORY.md` on Claude Code), append a `▸ CONTEXTO DEL HOST` section with a few signals of recent focus relevant to this workspace. No cheap host memory → **omit the section silently**. Never run an expensive transcript scan and **never ask**.
27
20
 
28
- > **Three axes, none of them a substitute for another.** A task completed answers *what work was done* (`tasks_done`/`tasks_total`); a phase validated answers *what functional state was demonstrated* (`phases_validated`/`phases_total`); a plan closed answers *whether the whole solution was validated* (`plan_state`). `progress_pct` stays checkbox-derived it never reads the phase marks. A plan at 100% with `phases_validated: 0` is **work implemented, not validated**: report it in both blocks and say so. `phases_total: 0` means a legacy plan with no phase marks — show only its checkbox progress, never a `0/0`.
21
+ > **The default view is what is LEFT TO DO** unrefined specs, refined specs with no plan, plans not `done`. Finished history, sessions and discarded items are still in the model; `--detail` brings them back. If the user asks about something the default hides, re-run with `--detail` instead of explaining its absence.
29
22
 
30
- > **`plan_state` is derived, never declared alone.** `open` (or nothing declared) keeps the plan in `▸ FALTA`, **including** a plan whose every box is ticked and every phase validated: that one carries `final_validation_pending: true` and is reported as `validación final pendiente` the work is complete, the final validation never ran. `done` reaches `▸ HECHO` only when the counters back the declaration. `inconsistent` means the document declares `done` while tasks or phases stay open, or declares a value nobody can read: it belongs in `▸ FALTA` **with the contradiction named** (`declara done con 2 tareas abiertas`), because only a human repairs it.
23
+ > **Automation reads JSON.** Through a pipe, and with `--json` or `--format json`, `aw status` emits the same machine-readable envelope it always has. `--detail` belongs to the human projection only.
31
24
 
32
- > **A blocked phase says what it waits on.** A `bloqueada` phase is the implemented-not-validated gap made explicit — every box ticked, its verification still pending — and belongs in both blocks: the work under `▸ HECHO`, the phase under `▸ FALTA` with its `> Bloqueo:` reason, so the reader knows the next action instead of only the state.
33
-
34
- > **The frontmatter governs spec maturity.** The spec's `status` (`draft` | `refining` | `ready-for-plan`) is the primary source, and readiness is never inferred from a section the spec happens to carry. A `status` that is absent, empty or unknown reads `draft` and the spec is reported as pending; only a spec with **no frontmatter at all** falls back to the two legacy marks (`## Refinement decisions`, `## Q&A traceability`).
35
-
36
- Suggested format (plain text; user-facing labels in Spanish):
37
-
38
- ```
39
- Workspace: <name>
40
-
41
- ▸ HECHO
42
- • plan <slug> — cerrado · <done>/<total> tareas (<pct>%) · <validadas>/<fases> fases validadas · <relative>
43
- • spec <slug> — lista para plan · <relative>
44
- • <folder> (<type>) — cerrada · <relative>
45
-
46
- ▸ FALTA
47
- • <folder> (<type>) — activa · <relative>
48
- • plan <slug> — <pendientes> tareas pendientes · <sin validar> fases sin validar
49
- • plan <slug> — validación final pendiente (todo validado, sin cierre)
50
- • plan <slug> — inconsistente: declara done con <n> tareas abiertas
51
- • F3 — Persistencia real — bloqueada: falta aplicar la migración
52
- • spec <slug> — borrador · <relative>
53
- • spec <slug> — <n> preguntas abiertas
54
-
55
- ▸ DESCARTÓ
56
- • <text> (<kind>) · <relative>
57
-
58
- ▸ CONTEXTO DEL HOST (solo si hay memoria barata; se omite si no)
59
- • <foco reciente / hilo relevante>
60
- ```
25
+ Uninitialized workspace (`initialized: false`, everything empty) say the folder is not an agent-workflow workspace and suggest `/w:workspace-init`.
61
26
 
62
27
  ## Plan mode
63
28
 
64
- Same as execution: run `aw status` (read-only) and show the summary. There are no changes to apply.
29
+ Same as execution: `aw status --format human` is read-only. There are no changes to apply.
65
30
 
66
31
  ## Resources
67
32
 
68
- - CLI: `aw status` (service `status-service`; dates via `humanize-es`)
33
+ - CLI: `aw status` (index `workline-index-service`, projection `status-service`; dates via `humanize-es`)
34
+ - Sibling: `aw resume` — what to pick up next, from the same index
69
35
  - Capability: `host-memory` ([`../harness/HARNESS.md`](../harness/HARNESS.md)) — cheap tier only, opportunistic, silent-omit, never asks
70
36
  - Design reference: `docs/referencias/workflow-skills/status.md`
71
-
72
- > **Note:** the host-context section is an opportunistic addendum — originally `/status` was a pure `aw status` dashboard. It composes the `host-memory` capability and is purely additive (the fast dashboard is unchanged).
@@ -5,8 +5,6 @@ allowed-tools:
5
5
  [
6
6
  "Bash",
7
7
  "Read",
8
- "Write",
9
- "Edit",
10
8
  ]
11
9
  ---
12
10
 
@@ -15,9 +13,11 @@ allowed-tools:
15
13
  Runs `aw workspace-init` to turn the current folder into a Workline workspace. A workspace has **1+ sources** (repos); "standalone" = a single source. There are no project/hub modes — the model is unified.
16
14
 
17
15
  ```bash
18
- aw workspace-init --source alias:path[:branch] [--proyecto <name>] [--main-branch <branch>] [--dry-run]
16
+ aw workspace-init --source alias:path[:branch] [--proyecto <name>] [--main-branch <branch>] [--dry-run] --format human
19
17
  ```
20
18
 
19
+ > **The CLI writes; this wrapper does not.** Every file below is created by `aw workspace-init` — `Write` and `Edit` are deliberately absent from `allowed-tools`. Use `--dry-run` to show the user what would land, then re-run without it. Relay the CLI's output instead of re-rendering it.
20
+
21
21
  ## Interactive steps
22
22
 
23
23
  1. **Detect/confirm sources** — the CLI detects the repo path(s); the user confirms aliases, paths and branches. Multiple `--source` accepted.
@@ -11,8 +11,27 @@
11
11
  | `PreToolUse` (`execute_sql`) | `hook sql-mutation-guard` | Blocks DML/DDL over MCP — reads only (DB scripts-only invariant). |
12
12
  | `PreToolUse` (Bash) | `hook git-commit-advisor` | **Advisory (does not block)**: warns if a `git commit` message lacks the active session's `sessionNNN` tag (traceability). Does **not** inspect `push`/`--amend`/`--no-verify`. |
13
13
  | `SessionEnd` | `auto-compact-on-close` | Writes `CHECKPOINT.md` on close — the resume key (*CHECKPOINT always* — chassis § Convergence / exit). |
14
- | `PreCompact` | `checkpoint-write` | Writes `CHECKPOINT.md` before the host compacts. |
15
- | `PostCompact` | `resume-summary` | Recovers the active loop state after a compact. |
14
+ | `PreCompact` | `checkpoint-write --can-pause` | Writes `CHECKPOINT.md` before the host compacts. |
15
+ | `PostCompact` | `resume-summary` | Recovers **the conversation's own** loop state after a compact. |
16
+
17
+ > **Conversation identity (spec 011).** The three lifecycle hooks act on **one**
18
+ > session — the conversation's own — never on "the first active one" and never
19
+ > on all of them. They resolve it with the canonical precedence: explicit
20
+ > `--code` → the conversation's durable association → the sole active session.
21
+ > The identity travels in the hook payload's `session_id` (read from stdin) or
22
+ > in `AW_CONTEXT_ID`; two signals naming different conversations fail with
23
+ > `CONTEXT_ID_CONFLICT` instead of picking one. The association lives in
24
+ > `.workflow/sessions/.bindings.json` keyed by the SHA-256 of that id — the raw
25
+ > value is never persisted.
26
+ >
27
+ > **Ambiguity is a capability question, not a guess.** `--can-pause` declares
28
+ > that *this host* can hold its compaction: Claude Code can, so the template
29
+ > passes it and `checkpoint-write` exits **2** with the candidate list instead of
30
+ > writing to an arbitrary session. A host that cannot pause omits the flag —
31
+ > its native compaction completes, and Workline reports
32
+ > `continuity: "degraded"` with `primary_session: null`, having written nothing.
33
+ > The flag is never inferred: guessing it produces false blocks. Per-host
34
+ > installation and transport belong to spec 010.
16
35
 
17
36
  > **What they enforce (host-level, blocking):** invariant **#4** (DB scripts-only) via `sql-mutation-guard` (blocks DML/DDL over MCP), and the *expected-branch* clause of **#5** via `branch-check` (blocks edits on the wrong branch). The rest of git-safe (`push`/`--amend`/`--no-verify`/`--force`) is **doctrinal** — `git-commit-advisor` only **warns**, it does not block; a host may add its own deny hook if it wants hard enforcement.
18
37
  >
@@ -62,7 +62,7 @@
62
62
  "hooks": [
63
63
  {
64
64
  "type": "command",
65
- "command": "agent-workflow checkpoint-write",
65
+ "command": "agent-workflow checkpoint-write --can-pause",
66
66
  "statusMessage": "Escribiendo CHECKPOINT.md antes de compactar...",
67
67
  "timeout": 10
68
68
  }
@@ -81,7 +81,7 @@
81
81
  },
82
82
  {
83
83
  "type": "prompt",
84
- "prompt": "Contexto compactado. El JSON anterior es output de `agent-workflow resume-summary`. Si hay `active_sessions`, reanudá el loop activo desde su CHECKPOINT.md y presentá un resumen. Si está vacío, terminá."
84
+ "prompt": "Contexto compactado. El JSON anterior es output de `agent-workflow resume-summary`. Si `continuity` es `ok`, reanudá el loop de `primary_session` desde su CHECKPOINT.md y presentá un resumen. Si `continuity` es `degraded`, NO reanudes ninguna sesión: `active_sessions` es un listado, no una identidad — mostrá `candidates` con su `action` y pedí al usuario que elija (después reintentá con `--code <NNN>`). Si no hay sesiones, terminá."
85
85
  }
86
86
  ]
87
87
  }
@@ -97,14 +97,13 @@ Outside an active session: relax to "1 line + no co-author"; the `session<NNN>`
97
97
 
98
98
  Autonomous `git merge` is forbidden (above), **but** resolving an **in-progress** merge (MERGE_HEAD), or one invoked by the user via `/w:fix-git`, **is** sanctioned work. **Workspace-agnostic**: it operates on any repo (no `.workflow/`, flows or sessions required).
99
99
 
100
- 1. **Detect + identify** with `aw merge-state [<path>|--source <alias>|--all]` (read-only): `is_merging`, `current_branch` (**destination / ours**), `merge_origin` (**origin / theirs**), `conflicted_files`. If `merge_origin` comes empty, check `.git/MERGE_MSG` or `git log --oneline -1 MERGE_HEAD`.
101
- 2. **Analyze each conflict's intent** **before** resolving — never pick a side blindly:
102
- - The three versions: `git show :1:<file>` (base) · `:2:<file>` (ours/destination) · `:3:<file>` (theirs/origin).
103
- - Each side's why: `git log --merge -p -- <file>`; the hunk's history on each branch.
104
- - The code around the marker (coherence with the rest of the file).
105
- 3. **Resolve** by editing the file (remove `<<<<<<<` / `=======` / `>>>>>>>`): pick **ours**, **theirs**, **combine** both intents, or **rewrite** to satisfy both. `git add <file>` what is resolved.
106
- 4. **Ask** (*structured-choice*) when the intent is **ambiguous** or both sides are **incoherent** with each other (not combinable without losing something): one content question per doubtful file/hunk (≤3 + `flow` control), options "Ours (`<destination>`)" / "Theirs (`<origin>`)" / "Combine" / "Edit manually". **Never invent** a resolution under real doubt.
107
- 5. **Proposed commit**: completing the merge is a `git commit` (the merge commit) → **propose-then-execute** like any commit (canonical format above; outside a session → 1 line without the `session<NNN>` tag; never `--no-verify`/`--amend`/`push`). The `git-commit-advisor` hook gates it.
100
+ **The mechanics live in the CLI** (`aw fix-git prepare | apply | commit`); what follows is the reasoning it expects from you. Never edit a conflicted file, `git add` or `git commit` by hand here — see [`../../commands/fix-git.md`](../../commands/fix-git.md) for the exact invocations.
101
+
102
+ 1. **Detect + identify**: `aw fix-git prepare` (read-only) returns the merge direction (**theirs → ours**), the conflicted paths and, per path, its three index stages with their blob hashes. `aw merge-state` remains the lighter inspector when you only need the state.
103
+ 2. **Analyze each conflict's intent** **before** resolving — never pick a side blindly. The request already carries the three versions: `base` (common ancestor), `ours` (destination) and `theirs` (origin). Add `git log --merge -p -- <file>` when the *why* of a hunk is not evident, and read the surrounding code for coherence.
104
+ 3. **Resolve** by composing the complete resolved file: pick **ours**, **theirs**, **combine** both intents, or **rewrite** to satisfy both — with no `<<<<<<<` / `=======` / `>>>>>>>` left. The CLI writes and stages it; a leftover marker is rejected, and so is a path that is no longer in conflict.
105
+ 4. **Ask** (*structured-choice*) when the intent is **ambiguous** or both sides are **incoherent** with each other (not combinable without losing something): answer `state: "ambiguous"` so nothing is written, then ask one content question per doubtful file/hunk (≤3 + `flow` control), options "Ours (`<destination>`)" / "Theirs (`<origin>`)" / "Combine" / "Edit manually". **Never invent** a resolution under real doubt. A **binary** conflict is never resolved automatically: propose `git checkout --ours|--theirs`.
106
+ 5. **Proposed commit**: completing the merge is a `git commit` (the merge commit) → **propose-then-execute** like any commit (canonical format above; outside a session 1 line without the `session<NNN>` tag; never `--no-verify`/`--amend`/`push`). It is a **separate, confirmed** invocation `aw fix-git commit --message "<msg>" --confirm` which refuses while any file stays unmerged. The `git-commit-advisor` hook gates it.
108
107
  6. **Escape hatch**: if the merge must not complete, `git merge --abort` **after user confirmation** (*structured-choice*) — leaves the repo as before the merge.
109
108
 
110
109
  > **Resume via git**: the merge state in `.git` (MERGE_HEAD + index) **is** the checkpoint; re-running `/w:fix-git` resumes from the remaining conflicts. No session, no artifact.