prove-cli 0.3.0__tar.gz → 0.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- prove_cli-0.4.1/.claude/skills/challenge/SKILL.md +290 -0
- prove_cli-0.4.1/.claude/skills/deviate/SKILL.md +176 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/recall/scripts/recall.sh +35 -13
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/remember/scripts/remember.sh +39 -13
- prove_cli-0.4.1/.claude/skills/scope/SKILL.md +167 -0
- prove_cli-0.4.1/.claude/skills/summarize-delivery/SKILL.md +440 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/CHANGELOG.md +51 -0
- prove_cli-0.4.1/CLAUDE.md +208 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/PKG-INFO +7 -4
- {prove_cli-0.3.0 → prove_cli-0.4.1}/README.md +6 -3
- {prove_cli-0.3.0 → prove_cli-0.4.1}/prove/explain/catalog.py +5 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/pyproject.toml +1 -1
- {prove_cli-0.3.0 → prove_cli-0.4.1}/uv.lock +1 -1
- prove_cli-0.3.0/CLAUDE.md +0 -28
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/agent-config/SKILL.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/agent-config/data/backend-fingerprints.yaml +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/agent-config/scripts/show.sh +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/ask-colleague/SKILL.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/ask-colleague/prompts/explore.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/ask-colleague/prompts/review.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/ask-colleague/prompts/write.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/ask-colleague/scripts/ask-colleague.sh +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/assign-to-workforce/SKILL.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/cicd/SKILL.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/cicd/scripts/_resolve-nick.sh +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/cicd/scripts/portability-lint.sh +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/cicd/scripts/pr-reply.sh +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/cicd/scripts/pr-status.sh +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/cicd/scripts/workflow.sh +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/communicate/SKILL.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/communicate/scripts/fetch-issues.sh +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/communicate/scripts/mesh-message.sh +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/communicate/scripts/post-comment.sh +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/communicate/scripts/post-issue.sh +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/communicate/scripts/templates/skill-new-brief.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/communicate/scripts/templates/skill-update-brief.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/doc-test-alignment/SKILL.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/doc-test-alignment/scripts/check.sh +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/pypi-maintainer/SKILL.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/pypi-maintainer/scripts/switch-source.sh +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/recall/SKILL.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/remember/SKILL.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/run-tests/SKILL.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/run-tests/scripts/test.sh +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/sonarclaude/SKILL.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/sonarclaude/scripts/sonar.sh +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/spec-to-plan/SKILL.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/spec-to-plan/scripts/spec-to-plan.sh +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/think/SKILL.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/think/scripts/think.sh +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/version-bump/SKILL.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills/version-bump/scripts/bump.py +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.claude/skills.local.yaml.example +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.flake8 +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.github/workflows/publish.yml +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.github/workflows/tests.yml +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.gitignore +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/.markdownlint-cli2.yaml +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/LICENSE +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/culture.yaml +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/docs/skill-sources.md +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/prove/__init__.py +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/prove/__main__.py +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/prove/cli/__init__.py +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/prove/cli/_commands/__init__.py +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/prove/cli/_commands/cli.py +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/prove/cli/_commands/doctor.py +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/prove/cli/_commands/explain.py +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/prove/cli/_commands/learn.py +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/prove/cli/_commands/overview.py +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/prove/cli/_commands/whoami.py +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/prove/cli/_errors.py +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/prove/cli/_output.py +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/prove/explain/__init__.py +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/sonar-project.properties +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/tests/__init__.py +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/tests/test_cli.py +0 -0
- {prove_cli-0.3.0 → prove_cli-0.4.1}/tests/test_cli_introspection.py +0 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: challenge
|
|
3
|
+
description: >
|
|
4
|
+
Run a risk-scaled blind-spot discovery pass over a converged, exported
|
|
5
|
+
frame BETWEEN /think and /spec-to-plan (the seventh origin skill, third
|
|
6
|
+
leg in flow order): pressure-test the spec through structured lenses,
|
|
7
|
+
route every finding back through the existing deterministic moves as
|
|
8
|
+
proposed-only content the human adjudicates, and on a clean pass record
|
|
9
|
+
the examined lenses/surfaces and residual uncertainty — never a claim
|
|
10
|
+
that there are no unknown unknowns. Use when the user says "challenge
|
|
11
|
+
this spec", "blind-spot pass", "pressure-test the frame", "what are we
|
|
12
|
+
missing", "unknown unknowns", or after /think exports and before
|
|
13
|
+
`devague plan new`. Authored and maintained in agentculture/devague
|
|
14
|
+
(origin = devague); guildmaster pulls this skill from here and broadcasts
|
|
15
|
+
it to the AgentCulture mesh — it is NOT vendored from guildmaster like
|
|
16
|
+
the inbound skills here.
|
|
17
|
+
type: command
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# challenge — hunt the blind spots before the plan inherits them
|
|
21
|
+
|
|
22
|
+
The skill is named **`challenge`**; it is the **blind-spot discovery leg** of
|
|
23
|
+
the devague method — the *seventh* origin skill, sitting *third* in flow
|
|
24
|
+
order, between the spec leg and the plan leg:
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
scope -> think -> challenge -> spec-to-plan -> assign-to-workforce -> deviate -> summarize-delivery
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Before this leg existed, a frame could converge on precisely stated claims
|
|
31
|
+
while the original framing was still incomplete: open questions only captured
|
|
32
|
+
uncertainty someone had already noticed — **nothing actively hunted omitted
|
|
33
|
+
dimensions, hidden dependencies, or assumptions shared by everyone in the
|
|
34
|
+
frame, and no record existed of which surfaces were ever examined**
|
|
35
|
+
(issue 73's problem statement). Strictly speaking, an unknown unknown cannot
|
|
36
|
+
be listed directly — once articulated, it becomes a known unknown. The useful
|
|
37
|
+
capability is therefore to **raise the odds of discovering blind spots and
|
|
38
|
+
lower the cost of the surprises that remain**, not to promise their
|
|
39
|
+
elimination.
|
|
40
|
+
|
|
41
|
+
That is the surprise-cost rationale: an articulated blind spot becomes a
|
|
42
|
+
known unknown the method can manage; an unexamined one surfaces later as a
|
|
43
|
+
mid-run `/deviate` or a production surprise. Discovery *before* planning is
|
|
44
|
+
cheaper than either — a proposed claim the human rejects costs minutes; the
|
|
45
|
+
same gap found mid-fan-out stops a wave, and found in production it costs
|
|
46
|
+
whatever the blast radius costs.
|
|
47
|
+
|
|
48
|
+
This doc is written for two readers. The **operator** — the main agent — runs
|
|
49
|
+
the pass: sweeps the lenses, drives the deterministic CLI move by move, and
|
|
50
|
+
proposes findings. The **gate-owning human** adjudicates: every finding lands
|
|
51
|
+
`proposed`, and confirming, rejecting, or resolving it is the human exercising
|
|
52
|
+
the existing **spec gate** (gate 1) — challenge adds no fourth gate, mirroring
|
|
53
|
+
how `/deviate` amends gate 2 rather than adding one.
|
|
54
|
+
|
|
55
|
+
## When it runs
|
|
56
|
+
|
|
57
|
+
The timing is a recorded decision — quote it, don't re-derive it:
|
|
58
|
+
|
|
59
|
+
> the challenge pass runs after /think exports: challenge the converged,
|
|
60
|
+
> exported frame before `devague plan new`; findings reopen the frame,
|
|
61
|
+
> reconverge, and re-export the same dated spec file — /think stays
|
|
62
|
+
> self-contained (resolves q1)
|
|
63
|
+
|
|
64
|
+
— decision c17 in `docs/specs/2026-07-15-challenge-skill.md`.
|
|
65
|
+
|
|
66
|
+
Concretely: `/think` finishes its own arc (converge, export) untouched. Then
|
|
67
|
+
`/challenge` pressure-tests the exported spec **before** `devague plan new`
|
|
68
|
+
seeds a plan from it. Findings land as proposed claims, honesty conditions,
|
|
69
|
+
questions, or parks — which reopens the frame — the human adjudicates, the
|
|
70
|
+
frame **reconverges**, and `devague export` **re-exports the same dated
|
|
71
|
+
file** (`docs/specs/<created-date>-<slug>.md`; exports are prefixed with the
|
|
72
|
+
frame's creation date, so a re-export overwrites in place rather than
|
|
73
|
+
spawning a duplicate). That reconverge-and-re-export loop repeats until the
|
|
74
|
+
pass's findings are all adjudicated and the spec artifact carries them.
|
|
75
|
+
|
|
76
|
+
## Proportionality — scale the pass to the risk
|
|
77
|
+
|
|
78
|
+
The pass is **mandatory but proportional**: lightweight for ordinary work,
|
|
79
|
+
rigorous for high-risk work (integration option 1 from issue 73, per the
|
|
80
|
+
issue author — a distinct operator skill, no new CLI engine until the
|
|
81
|
+
workflow proves it needs one). Which work is high-risk is likewise a recorded
|
|
82
|
+
decision:
|
|
83
|
+
|
|
84
|
+
> the named escalation signals that deepen the pass from lightweight to
|
|
85
|
+
> rigorous: migrations, security-sensitive work, distributed state, hardware,
|
|
86
|
+
> destructive operations, other hard-to-reverse changes, concurrency hazards,
|
|
87
|
+
> and any surface that can lose user data (resolves q3)
|
|
88
|
+
|
|
89
|
+
— decision c19 in `docs/specs/2026-07-15-challenge-skill.md`.
|
|
90
|
+
|
|
91
|
+
If **any** escalation signal applies, run the rigorous form: every lens,
|
|
92
|
+
deliberate counter-evidence hunting, and cheap probes where they would settle
|
|
93
|
+
a real question. If none applies, a lightweight sweep — one pass over the
|
|
94
|
+
lenses against the exported spec, minutes not hours — satisfies the method.
|
|
95
|
+
Lightweight never means skipped: even the lightest pass leaves durable
|
|
96
|
+
records (see the hard rules).
|
|
97
|
+
|
|
98
|
+
## The lenses
|
|
99
|
+
|
|
100
|
+
Sweep the exported spec, the live frame, and the surfaces the idea touches
|
|
101
|
+
through these structured lenses (from issue 73):
|
|
102
|
+
|
|
103
|
+
- **adjacent systems and hidden dependencies** — what else reads, writes, or
|
|
104
|
+
assumes the thing being changed;
|
|
105
|
+
- **unstated assumptions and missing counter-evidence** — what everyone in
|
|
106
|
+
the frame believes without a claim saying so, and what was never checked
|
|
107
|
+
because nobody argued the other side;
|
|
108
|
+
- **overlooked actors, lifecycle stages, data flows, and failure modes** —
|
|
109
|
+
who and what the frame forgot: other users, upgrade/downgrade paths,
|
|
110
|
+
half-completed operations;
|
|
111
|
+
- **security, migration, concurrency, operations, and reversibility** — the
|
|
112
|
+
classic hard surfaces, each also an escalation signal when present;
|
|
113
|
+
- **missing observability, containment, rollback, and recovery paths** —
|
|
114
|
+
when the surprise happens anyway, how it is seen, bounded, and undone;
|
|
115
|
+
- **cheap probes or experiments** — small, scratch-space checks that could
|
|
116
|
+
expose a surprise now instead of mid-run (probes never mutate the repo or
|
|
117
|
+
`.devague/` state).
|
|
118
|
+
|
|
119
|
+
## The method
|
|
120
|
+
|
|
121
|
+
1. **Confirm the entry condition.** A converged frame that `/think` has
|
|
122
|
+
already exported, and no plan seeded from it yet (`devague status` shows
|
|
123
|
+
where the frame stands; the exported spec-md is the artifact under
|
|
124
|
+
challenge).
|
|
125
|
+
2. **Set the depth.** Check the idea against the c19 escalation signals
|
|
126
|
+
above. Any hit → rigorous; none → lightweight. Say which you chose and
|
|
127
|
+
why — the depth decision is part of the pass's record.
|
|
128
|
+
3. **Sweep the lenses read-only.** Read the exported spec claim by claim,
|
|
129
|
+
the frame's parked vagueness and resolved questions, and the actual
|
|
130
|
+
surfaces the idea touches. Nothing mutates during the sweep; the only
|
|
131
|
+
mutations are the deterministic moves that record findings.
|
|
132
|
+
4. **Route every finding through an existing move.** Use the routing table
|
|
133
|
+
below. Everything the agent proposes carries `--origin llm` and lands
|
|
134
|
+
`proposed` — the pass cannot silently convert speculation into confirmed
|
|
135
|
+
requirements.
|
|
136
|
+
5. **Let the human adjudicate.** `devague review` lists every proposal with
|
|
137
|
+
ids; `devague confirm` / `devague reject` / `devague question --resolve`
|
|
138
|
+
are user-only decisions. This is the existing spec gate doing its job.
|
|
139
|
+
6. **Reconverge and re-export.** `devague converge`, then `devague export` —
|
|
140
|
+
the same dated spec file now carries the adjudicated findings and the
|
|
141
|
+
pass's provenance (the exported spec renders scope entries in its
|
|
142
|
+
Scope exploration section).
|
|
143
|
+
7. **On a clean pass, record the pass itself.** A sweep that finds nothing
|
|
144
|
+
still records which lenses and surfaces were examined (`devague scope`
|
|
145
|
+
entries, one per lens/surface, e.g. `challenge pass / concurrency lens:
|
|
146
|
+
devague/store.py`) and what residual uncertainty remains (`park`). A bare
|
|
147
|
+
"no issues found" is not an outcome this skill produces.
|
|
148
|
+
|
|
149
|
+
## Where findings land
|
|
150
|
+
|
|
151
|
+
Challenge keeps **no parallel prose-only artifact** — the frame is the
|
|
152
|
+
record, and every output category from issue 73 has an existing deterministic
|
|
153
|
+
move to land in:
|
|
154
|
+
|
|
155
|
+
| Output category (issue 73) | What it is | Landing move |
|
|
156
|
+
|----------------------------|------------|--------------|
|
|
157
|
+
| known facts | something the pass established, with provenance | `capture --kind requirement` / `--kind decision` / `--kind boundary` (`--origin llm` → lands `proposed`) |
|
|
158
|
+
| assumptions | beliefs the frame leaned on unstated | `capture --kind assumption --origin llm`, then pressure-test with `interrogate --honesty` / `--hard-question` / `--contradicts` |
|
|
159
|
+
| known unknowns / open questions | articulated uncertainty | `question "<text>"` when it needs a user decision; `park --kind unknown_nonblocking\|unknown_blocking` when not decidable now |
|
|
160
|
+
| unexamined surfaces | what this pass did not (or could not) look at | `devague scope "<surface>" --finding "<what was and wasn't examined, and why>"` |
|
|
161
|
+
| residual surprise risk | uncertainty that survives the pass | `park` on the frame while speccing; `devague plan risk --kind <kind>` once the plan exists |
|
|
162
|
+
| resilience measures | containment, rollback, recovery the surprise cost demands | spec-side `capture --kind requirement` / `--kind boundary`; plan-side `devague plan risk` (see below) |
|
|
163
|
+
|
|
164
|
+
Every finding names the **lens and surface** it came from (the
|
|
165
|
+
`challenge pass / <lens>: <surface>` convention in scope entries; provenance
|
|
166
|
+
citations inside claim text). That provenance bar is how the method hunts
|
|
167
|
+
blind spots **without encouraging speculative issue generation** — a finding
|
|
168
|
+
you cannot trace to something you actually read is speculation, not a
|
|
169
|
+
finding.
|
|
170
|
+
|
|
171
|
+
## Resilience placement — spec-side or plan-side
|
|
172
|
+
|
|
173
|
+
Where a resilience measure lands is a recorded decision:
|
|
174
|
+
|
|
175
|
+
> resilience measures land in both spec and plan by nature: spec-side as
|
|
176
|
+
> requirement/boundary claims when they change what to build, plan-side as
|
|
177
|
+
> plan risks or tasks when they change how to build it — the skill coaches
|
|
178
|
+
> which is which (resolves q2)
|
|
179
|
+
|
|
180
|
+
— decision c18 in `docs/specs/2026-07-15-challenge-skill.md`.
|
|
181
|
+
|
|
182
|
+
The coaching: ask *"does this change **what** ships, or **how** it gets
|
|
183
|
+
built?"* A rollback path the user needs, a fail-closed version check, a
|
|
184
|
+
containment boundary — those change the product: `capture` them spec-side as
|
|
185
|
+
`requirement` / `boundary` claims so the re-exported spec carries them.
|
|
186
|
+
A staging sequence, a merge-order constraint, an uncertainty the workforce
|
|
187
|
+
must build around — those change the build: land them plan-side via
|
|
188
|
+
`devague plan risk --kind <kind>` (blocking or nonblocking, honestly chosen)
|
|
189
|
+
once `/spec-to-plan` seeds the plan, where the plan's convergence gate keeps
|
|
190
|
+
blocking risks visible until resolved.
|
|
191
|
+
|
|
192
|
+
## Hard rules (do not violate)
|
|
193
|
+
|
|
194
|
+
- **Never conclude there are no unknown unknowns.** Not after a rigorous
|
|
195
|
+
pass, not after a clean one. The only honest clean-pass output is a record
|
|
196
|
+
of which lenses and surfaces were examined — `devague scope` entries — plus
|
|
197
|
+
the residual uncertainty that remains — `park` — so the pass leaves durable
|
|
198
|
+
provenance instead of a comforting absolute (issue 73 success criteria;
|
|
199
|
+
the anti-fabrication contract in `docs/llm-guidance.md`).
|
|
200
|
+
- **LLM-origin findings stay proposed until the user confirms.** Every
|
|
201
|
+
finding the agent proposes carries `--origin llm` and lands `proposed`;
|
|
202
|
+
only the user's `confirm` makes it real. The pass must not be able to
|
|
203
|
+
silently convert speculation into confirmed requirements.
|
|
204
|
+
- **Findings route through existing deterministic moves only.** `capture`,
|
|
205
|
+
`interrogate`, `question`, `park`, `devague scope`, `devague plan risk` —
|
|
206
|
+
nothing else. No parallel prose artifact, no new CLI verb, engine, or
|
|
207
|
+
state model (issue 20; issue 73's stated preference). If it didn't land in
|
|
208
|
+
a move, it didn't land.
|
|
209
|
+
- **Provenance on every finding.** Name the lens and the surface it came
|
|
210
|
+
from. If you didn't read it, don't claim it — same bar as `/scope`.
|
|
211
|
+
- **Proportional, never skipped.** Lightweight is the floor, not an
|
|
212
|
+
exemption; any c19 escalation signal makes the rigorous form mandatory.
|
|
213
|
+
Skipping the pass entirely is not a depth setting.
|
|
214
|
+
- **Not a fourth standing gate.** The three human gates stay: exported spec,
|
|
215
|
+
implementation split plan, final PR. Challenge output is adjudicated
|
|
216
|
+
inside the existing spec gate — mirroring how `/deviate` amends gate 2
|
|
217
|
+
rather than adding one.
|
|
218
|
+
- **The sweep is read-only until it routes.** Reading spec, frame, and
|
|
219
|
+
surfaces never edits files or state; probes run in scratch space. The only
|
|
220
|
+
mutations are the recording moves themselves.
|
|
221
|
+
|
|
222
|
+
## Worked example
|
|
223
|
+
|
|
224
|
+
Challenging the exported spec for a store-schema migration (illustrative
|
|
225
|
+
slug `store-schema-v3`) — "migrations" and "any surface that can lose user
|
|
226
|
+
data" are both c19 escalation signals, so the pass runs rigorous:
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
# Entry condition: /think exported docs/specs/2026-07-15-store-schema-v3.md
|
|
230
|
+
# and no plan exists yet. Depth: rigorous (migration + data-loss signals).
|
|
231
|
+
|
|
232
|
+
# adjacent-systems lens: an older installed devague reads the same store
|
|
233
|
+
devague capture --origin llm --kind assumption "older installed devague binaries refuse a v3 store via the fail-closed schema_version check in devague/store.py"
|
|
234
|
+
devague interrogate c9 --origin llm --honesty "a v2-reading binary pointed at a v3 store exits with the version hint, not a traceback"
|
|
235
|
+
devague scope "challenge pass / adjacent-systems lens: devague/store.py schema_version gate" --finding "older binaries fail closed on v3; seeded the compat assumption" --seeds c9
|
|
236
|
+
|
|
237
|
+
# failure-mode lens: the migration can die halfway
|
|
238
|
+
devague capture --origin llm --kind requirement "migration writes to a temp file and renames — a killed run never leaves a half-written store"
|
|
239
|
+
|
|
240
|
+
# overlooked-actors lens: needs a user decision, not a guess
|
|
241
|
+
devague question "do mesh agents share one store, or does each checkout own its own?"
|
|
242
|
+
|
|
243
|
+
# reversibility lens: genuinely unknown, not decidable now
|
|
244
|
+
devague park "whether a v3->v2 downgrade path is ever needed" --kind unknown_nonblocking
|
|
245
|
+
|
|
246
|
+
# concurrency lens found nothing — record the clean pass, not a conclusion
|
|
247
|
+
devague scope "challenge pass / concurrency lens: devague/store.py + delivery_store.py" --finding "single-writer CLI, no locking today; clean pass — residual risk only if two agents ever share a checkout"
|
|
248
|
+
|
|
249
|
+
# --- HUMAN adjudicates: the existing spec gate at work ---
|
|
250
|
+
devague review
|
|
251
|
+
devague confirm c9 h4 c10
|
|
252
|
+
devague question --resolve q1 --decision "each checkout owns its own store"
|
|
253
|
+
|
|
254
|
+
# Reconverge and re-export — the SAME dated file, now carrying the pass
|
|
255
|
+
devague converge
|
|
256
|
+
devague export
|
|
257
|
+
|
|
258
|
+
# Residual risk that changes HOW to build lands plan-side once
|
|
259
|
+
# /spec-to-plan seeds the plan:
|
|
260
|
+
devague plan new --frame store-schema-v3
|
|
261
|
+
devague plan risk "two agents sharing a checkout could interleave store writes mid-migration" --kind unknown_nonblocking
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Every finding above is traceable to a lens and a surface; the clean lens is
|
|
265
|
+
recorded as examined rather than silently dropped; and nothing the agent
|
|
266
|
+
proposed became confirmed without the human's `confirm`.
|
|
267
|
+
|
|
268
|
+
## After the pass — hand off to /spec-to-plan
|
|
269
|
+
|
|
270
|
+
Once the frame reconverges and the same dated spec file is re-exported, the
|
|
271
|
+
pass is done — the examined surfaces, residual uncertainty, and adjudicated
|
|
272
|
+
findings all live in frame state and render into the spec artifact. Continue
|
|
273
|
+
with `/spec-to-plan` as usual: the plan seeds from the challenged frame, and
|
|
274
|
+
any residual surprise risk you routed plan-side lands via
|
|
275
|
+
`devague plan risk` as first-class plan state. If a surprise still gets
|
|
276
|
+
through mid-fan-out, that is `/deviate`'s job — and every approved `dN`
|
|
277
|
+
deviation record is evidence for what the *next* challenge pass's lenses
|
|
278
|
+
should look harder at.
|
|
279
|
+
|
|
280
|
+
## Provenance
|
|
281
|
+
|
|
282
|
+
This is a **first-party** skill — its origin is `agentculture/devague`, the
|
|
283
|
+
*seventh* in the outbound family after `/scope`, `/think`, `/spec-to-plan`,
|
|
284
|
+
`/assign-to-workforce`, `/deviate`, and `/summarize-delivery`, sitting third
|
|
285
|
+
in flow order as the blind-spot discovery leg between `/think` and
|
|
286
|
+
`/spec-to-plan`. guildmaster pulls it from here and broadcasts it to the
|
|
287
|
+
AgentCulture mesh; because devague is upstream, it is **never re-vendored
|
|
288
|
+
back** from guildmaster's re-broadcast copy. The `cite, don't import` policy
|
|
289
|
+
still holds: downstream repos copy it, they don't symlink or depend on it.
|
|
290
|
+
See `docs/skill-sources.md`.
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: deviate
|
|
3
|
+
description: >
|
|
4
|
+
Stop an in-flight assign-to-workforce run the moment execution must diverge
|
|
5
|
+
from the confirmed plan, get explicit human approval for the divergence, and
|
|
6
|
+
record it as a first-class, append-only deviation record via `devague
|
|
7
|
+
deviate` before resuming — never fold a deviation silently into drift after
|
|
8
|
+
the fact. Use when the user says "deviate from the plan", "we need to change
|
|
9
|
+
the plan mid-run", "record a deviation", "this isn't matching the plan
|
|
10
|
+
anymore", or when a task agent discovers the confirmed plan no longer
|
|
11
|
+
matches reality partway through a workforce run. Authored and maintained in
|
|
12
|
+
agentculture/devague (origin = devague); guildmaster pulls this skill from
|
|
13
|
+
here and broadcasts it to the AgentCulture mesh — it is NOT vendored from
|
|
14
|
+
guildmaster like the inbound skills here.
|
|
15
|
+
type: command
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# deviate — record an approved mid-run departure from the confirmed plan
|
|
19
|
+
|
|
20
|
+
The skill is named **`deviate`**; it is the **execution-time leg** of the
|
|
21
|
+
devague method — the *sixth* leg, sitting between the two execution skills:
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
scope -> think -> spec-to-plan -> assign-to-workforce -> deviate -> summarize-delivery
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Where `/assign-to-workforce` fans out a converged plan's waves and
|
|
28
|
+
`/summarize-delivery` closes the loop afterward, `/deviate` runs **during**
|
|
29
|
+
the fan-out, at the exact moment reality stops matching the plan the human
|
|
30
|
+
approved at gate 2 (the implementation split plan). It is not a new standing
|
|
31
|
+
gate — it is the human owner of gate 2 **amending** the approved split
|
|
32
|
+
mid-flight, scoped to the one deviation in front of them.
|
|
33
|
+
|
|
34
|
+
The plan the user confirmed is a contract. Task agents hit constraints,
|
|
35
|
+
discover a dependency was wrong, or find the acceptance criteria no longer
|
|
36
|
+
make sense once code is in front of them. Until this skill existed, that
|
|
37
|
+
reality either silently reshaped what got built (undocumented drift) or the
|
|
38
|
+
run stalled with no recorded path forward. `/deviate` is that path: the
|
|
39
|
+
departure is named, approved, and recorded **before** anyone keeps building
|
|
40
|
+
against it.
|
|
41
|
+
|
|
42
|
+
## The method
|
|
43
|
+
|
|
44
|
+
1. **STOP the run.** The moment a task agent (or the main agent) discovers
|
|
45
|
+
the confirmed plan no longer matches what needs to happen, halt — do not
|
|
46
|
+
keep implementing against the stale contract and do not let the fan-out
|
|
47
|
+
continue past this task.
|
|
48
|
+
2. **Present what, why, and what it affects.** Lay out, for the human:
|
|
49
|
+
- **what** is diverging — the specific change from the confirmed task(s);
|
|
50
|
+
- **why** — the constraint or discovery that forced it;
|
|
51
|
+
- **what it affects** — the plan item ref(s) involved (`--task`), any
|
|
52
|
+
other task ids or coverage targets it touches (`--affects`), and which
|
|
53
|
+
acceptance criteria are no longer accurate.
|
|
54
|
+
3. **Get explicit human approval.** This is the one non-negotiable step. A
|
|
55
|
+
deviation is not real until a human says yes to *this specific* departure
|
|
56
|
+
— not a standing blanket permission, not an inference from silence.
|
|
57
|
+
4. **Record it via `devague deviate`.** Once approved, record the deviation
|
|
58
|
+
as a first-class ledger entry (never edit the plan itself — the plan
|
|
59
|
+
stays the untouched historical contract; see `devague/delivery.py`). An
|
|
60
|
+
`--origin llm` record lands `proposed` and still needs the user's
|
|
61
|
+
`--confirm` — recording is not the same as approval landing as final.
|
|
62
|
+
5. **Adjust the affected task briefs.** Update the working instructions the
|
|
63
|
+
task agent(s) are building against so they reflect the approved
|
|
64
|
+
departure, not the stale plan text.
|
|
65
|
+
6. **Resume.** Only after the record exists (and, for an `llm`-origin record,
|
|
66
|
+
only after it is confirmed) does the fan-out continue.
|
|
67
|
+
|
|
68
|
+
Deviations are never silently folded into drift after the fact — by the time
|
|
69
|
+
`/summarize-delivery` runs, every departure from the plan already has a
|
|
70
|
+
`dN` record with a reason, an approval, and an optional classification. The
|
|
71
|
+
delivery summary quotes these records; it does not reconstruct drift from
|
|
72
|
+
memory.
|
|
73
|
+
|
|
74
|
+
## The shipped CLI surface
|
|
75
|
+
|
|
76
|
+
This skill invokes the CLI directly and stays self-contained (if `devague`
|
|
77
|
+
isn't on your PATH: `uv tool install devague`). Deviation state persists
|
|
78
|
+
under `.devague/deliveries/<plan-slug>.json` — a peer of the plan store, keyed
|
|
79
|
+
by the plan slug, and never touches the plan JSON itself.
|
|
80
|
+
|
|
81
|
+
| Move | What it does |
|
|
82
|
+
|------|---------------|
|
|
83
|
+
| `devague deviate "<what>" --task <tN> --reason "<text>"` | Record a deviation against plan item `<tN>`. User-origin (the default) auto-approves. |
|
|
84
|
+
| `devague deviate "<what>" --task <tN> --reason "<text>" --affects <ref> [<ref> ...]` | Same, also naming every other plan item ref or coverage target the deviation touches (repeatable). |
|
|
85
|
+
| `devague deviate "<what>" --task <tN> --reason "<text>" --classification acceptable\|risky\|needs-follow-up` | Same, tagging the deviation with the classification the drift-entry contract consumes downstream. |
|
|
86
|
+
| `devague deviate "<what>" --task <tN> --reason "<text>" --origin llm` | An LLM-proposed record; lands `proposed`, not `approved`. |
|
|
87
|
+
| `devague deviate --confirm <dN>` | User-only: approve a `proposed` deviation. |
|
|
88
|
+
| `devague deviate --reject <dN>` | User-only: reject a `proposed` (or any) deviation. |
|
|
89
|
+
| `devague deviate --list [--json]` | Read every recorded deviation back (also the default action with no positional/flag). |
|
|
90
|
+
| `devague deviate ... --plan <slug>` | Target a plan other than the current one. |
|
|
91
|
+
|
|
92
|
+
`--reason` is required on every record — omitting it is refused with a hint.
|
|
93
|
+
`--task` naming the plan item ref is likewise required.
|
|
94
|
+
|
|
95
|
+
## Hard rules (do not violate)
|
|
96
|
+
|
|
97
|
+
- **Never record a deviation the human did not approve.** `devague deviate`
|
|
98
|
+
without `--origin llm` auto-approves the instant it is run — so a
|
|
99
|
+
user-origin record IS the approval. Only run it after the human has said
|
|
100
|
+
yes to this specific departure, never preemptively "to be safe."
|
|
101
|
+
- **Never continue past a refused approval.** If the human does not approve,
|
|
102
|
+
the run stays stopped on that task. Do not record the deviation anyway, do
|
|
103
|
+
not quietly implement the diverging approach, and do not advance the wave.
|
|
104
|
+
- **LLM-origin records stay proposed until the user confirms.** `--origin
|
|
105
|
+
llm` lands `proposed`; only `devague deviate --confirm <dN>` (user-only)
|
|
106
|
+
makes it `approved`. Same anti-fabrication contract as every other origin
|
|
107
|
+
in the method — an agent's own proposal never self-confirms.
|
|
108
|
+
- **Deviations are never silently folded into drift after the fact.** Every
|
|
109
|
+
departure from the confirmed plan gets a `dN` record at the moment it
|
|
110
|
+
happens — not reconstructed from memory when `/summarize-delivery` runs
|
|
111
|
+
later.
|
|
112
|
+
- **The CLI stays non-orchestrating (issue #20).** `devague deviate` records
|
|
113
|
+
a decision the human already made; it does not spawn agents, gate merges,
|
|
114
|
+
mark tasks done, or make the approval decision itself. Recording is
|
|
115
|
+
deterministic — no LLM calls inside the CLI.
|
|
116
|
+
- **This is not a fourth standing gate.** `/assign-to-workforce`'s three
|
|
117
|
+
human gates are the exported spec, the implementation split plan, and the
|
|
118
|
+
final PR. `/deviate` does not add a fourth — it is the human owner of gate
|
|
119
|
+
2 amending the approved split for one scoped, in-flight decision.
|
|
120
|
+
|
|
121
|
+
## Worked example
|
|
122
|
+
|
|
123
|
+
Mid-fan-out on task `t4`, the task agent discovers the acceptance criteria
|
|
124
|
+
assumed a helper that task `t2` never actually shipped:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# 1. STOP — the main agent halts t4's worktree before more code lands
|
|
128
|
+
# against a criterion that can't be met as written.
|
|
129
|
+
|
|
130
|
+
# 2. Present what/why/what-it-affects to the human:
|
|
131
|
+
# what: t4's acceptance criterion 2 assumes a `--json` flag on a
|
|
132
|
+
# helper that t2 shipped without one
|
|
133
|
+
# why: t2's scope was cut to land its wave on time
|
|
134
|
+
# affects: t4 (this task), and coverage target c9 (the criterion in
|
|
135
|
+
# question)
|
|
136
|
+
|
|
137
|
+
# --- HUMAN: approves dropping the --json assumption from t4's criterion ---
|
|
138
|
+
|
|
139
|
+
# 3. Record the approved deviation
|
|
140
|
+
devague deviate "drop the --json assumption from t4's acceptance criterion" \
|
|
141
|
+
--task t4 --reason "t2 shipped its helper without --json to land its wave on time" \
|
|
142
|
+
--affects t2 --affects c9 --classification acceptable
|
|
143
|
+
|
|
144
|
+
# 4. Adjust t4's working brief to match what was approved, then resume the
|
|
145
|
+
# task agent against the corrected instruction.
|
|
146
|
+
|
|
147
|
+
# Read the ledger back at any point:
|
|
148
|
+
devague deviate --list
|
|
149
|
+
devague deviate --list --json
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
If the agent had proposed the record itself (`--origin llm`), the same
|
|
153
|
+
record would land `proposed` and need an explicit
|
|
154
|
+
`devague deviate --confirm d1` from the user before `/summarize-delivery`
|
|
155
|
+
could cite it as approved.
|
|
156
|
+
|
|
157
|
+
## After recording — resume, then hand off to /summarize-delivery
|
|
158
|
+
|
|
159
|
+
Once the affected task briefs are adjusted and the fan-out resumes, nothing
|
|
160
|
+
further is needed from this skill — the record already lives in the delivery
|
|
161
|
+
store. When the run reaches `/summarize-delivery`, that skill's Drift From
|
|
162
|
+
Plan and Mid-work Decisions sections quote these records by their `dN` id
|
|
163
|
+
instead of reconstructing drift from memory, so the connective tissue between
|
|
164
|
+
the confirmed plan and the delivery summary is the ledger this skill wrote,
|
|
165
|
+
not anyone's recollection of the run.
|
|
166
|
+
|
|
167
|
+
## Provenance
|
|
168
|
+
|
|
169
|
+
This is a **first-party** skill — its origin is `agentculture/devague`, the
|
|
170
|
+
*sixth* in the outbound family after `/scope`, `/think`, `/spec-to-plan`,
|
|
171
|
+
`/assign-to-workforce`, and `/summarize-delivery`, covering the execution-time
|
|
172
|
+
leg that runs inside an `/assign-to-workforce` fan-out. guildmaster pulls it
|
|
173
|
+
from here and broadcasts it to the AgentCulture mesh; because devague is
|
|
174
|
+
upstream, it is **never re-vendored back** from guildmaster's re-broadcast
|
|
175
|
+
copy. The `cite, don't import` policy still holds: downstream repos copy it,
|
|
176
|
+
they don't symlink or depend on it. See `docs/skill-sources.md`.
|
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
# forwards every flag verbatim — so `recall.sh "<query>" --mode hybrid --json`
|
|
7
7
|
# is exactly `eidetic recall "<query>" --mode hybrid --json`.
|
|
8
8
|
#
|
|
9
|
-
# The store is the files backend
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
9
|
+
# The store is the files backend. Default location resolves per-operation:
|
|
10
|
+
# PUBLIC records inside a git repo → <repo-root>/.eidetic/memory (committed,
|
|
11
|
+
# team-shared); PRIVATE records, or any record outside a git repo →
|
|
12
|
+
# $HOME/.eidetic/memory (never committed). Recall reads both stores and merges.
|
|
13
|
+
# An explicit EIDETIC_DATA_DIR wins and short-circuits to that single dir.
|
|
13
14
|
|
|
14
15
|
set -euo pipefail
|
|
15
16
|
|
|
@@ -34,12 +35,10 @@ resolve_eidetic() {
|
|
|
34
35
|
fi
|
|
35
36
|
dir=$(dirname "$dir")
|
|
36
37
|
done
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
The console script is `eidetic` (dist name: eidetic-cli).
|
|
42
|
-
EOF
|
|
38
|
+
# In a vendored copy there is no eidetic-cli checkout to fall back to, so the
|
|
39
|
+
# only honest remedy is to install the CLI. One `error:` + one `hint:` line.
|
|
40
|
+
printf 'error: eidetic CLI not found.\n' >&2
|
|
41
|
+
printf 'hint: install it with: uv tool install eidetic-cli (or pipx install eidetic-cli); the console script is eidetic.\n' >&2
|
|
43
42
|
return 1
|
|
44
43
|
}
|
|
45
44
|
|
|
@@ -65,10 +64,17 @@ EOF
|
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
case "${1:-}" in
|
|
68
|
-
-h | --help
|
|
67
|
+
-h | --help)
|
|
69
68
|
usage
|
|
70
69
|
exit 0
|
|
71
70
|
;;
|
|
71
|
+
"")
|
|
72
|
+
# A missing query is a usage error, not success. The bareword `help` is
|
|
73
|
+
# a legitimate search term, so it is intentionally NOT a usage alias.
|
|
74
|
+
printf 'error: no query given.\n' >&2
|
|
75
|
+
printf 'hint: recall.sh "<query>" [--mode ...] [--json]; run recall.sh --help for usage.\n' >&2
|
|
76
|
+
exit 1
|
|
77
|
+
;;
|
|
72
78
|
esac
|
|
73
79
|
|
|
74
80
|
resolve_eidetic || exit 2
|
|
@@ -100,9 +106,12 @@ resolve_scope() {
|
|
|
100
106
|
# inline `# comment` or trailing space can't bleed into the scope),
|
|
101
107
|
# then strip surrounding quotes only — matching the canonical parser
|
|
102
108
|
# in .claude/skills/cicd/scripts/_resolve-nick.sh.
|
|
109
|
+
# `|| true`: under `set -o pipefail`, `head -n1` closing the pipe
|
|
110
|
+
# early can SIGPIPE `sed`, making the substitution non-zero and
|
|
111
|
+
# aborting the script. An empty parse must yield "" here, not exit.
|
|
103
112
|
suffix=$(sed -n \
|
|
104
113
|
's/^[[:space:]]*-\{0,1\}[[:space:]]*suffix:[[:space:]]*\([^[:space:]]*\).*/\1/p' \
|
|
105
|
-
"$dir/culture.yaml" | head -n1 | tr -d "\"'")
|
|
114
|
+
"$dir/culture.yaml" | head -n1 | tr -d "\"'" || true)
|
|
106
115
|
break
|
|
107
116
|
fi
|
|
108
117
|
dir=$(dirname "$dir")
|
|
@@ -127,7 +136,20 @@ if ! has_flag --scope "$@"; then
|
|
|
127
136
|
EIDETIC_SCOPE=$(resolve_scope)
|
|
128
137
|
if [ -n "$EIDETIC_SCOPE" ]; then
|
|
129
138
|
SCOPE_ARGS+=(--scope "$EIDETIC_SCOPE")
|
|
130
|
-
|
|
139
|
+
# rollout-cli eidetic-memory recipe POLICY OVERRIDE (not eidetic's
|
|
140
|
+
# upstream private default): default to PUBLIC, so a plain recall queries
|
|
141
|
+
# the in-repo public pool (<repo>/.eidetic/memory) this repo writes to.
|
|
142
|
+
# Pass --visibility private to also surface this agent's private ($HOME)
|
|
143
|
+
# notes. The two-store read model reads both dirs regardless.
|
|
144
|
+
has_flag --visibility "$@" || SCOPE_ARGS+=(--visibility public)
|
|
145
|
+
elif ! has_flag --visibility "$@"; then
|
|
146
|
+
# No suffix AND no explicit --visibility: the query runs against
|
|
147
|
+
# eidetic's own default (scope=default, visibility=public), not this
|
|
148
|
+
# agent's private personal scope — so an empty result isn't silently
|
|
149
|
+
# misread. Warn on stderr (stdout stays clean for --json). Warn ONLY
|
|
150
|
+
# here: an explicit --scope (outer guard) or --visibility (this guard) is
|
|
151
|
+
# a deliberate choice, honored verbatim, so either flag silences this.
|
|
152
|
+
printf 'warning: no culture.yaml suffix resolved; querying the public default scope rather than a private personal scope. Pass --scope or --visibility to target deliberately.\n' >&2
|
|
131
153
|
fi
|
|
132
154
|
fi
|
|
133
155
|
|
|
@@ -12,10 +12,11 @@
|
|
|
12
12
|
# Upsert is idempotent by id (and dedups by content hash): re-remembering the
|
|
13
13
|
# same record updates it in place, never duplicates.
|
|
14
14
|
#
|
|
15
|
-
# The store is the files backend
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
15
|
+
# The store is the files backend. Default location resolves per-operation:
|
|
16
|
+
# PUBLIC records inside a git repo → <repo-root>/.eidetic/memory (committed,
|
|
17
|
+
# team-shared); PRIVATE records, or any record outside a git repo →
|
|
18
|
+
# $HOME/.eidetic/memory (never committed). An explicit EIDETIC_DATA_DIR still
|
|
19
|
+
# wins and short-circuits to that single dir. Use --backend mongo|neo4j (with
|
|
19
20
|
# EIDETIC_MONGO_URI / NEO4J_URI) for a server-backed shared store.
|
|
20
21
|
|
|
21
22
|
set -euo pipefail
|
|
@@ -40,12 +41,10 @@ resolve_eidetic() {
|
|
|
40
41
|
fi
|
|
41
42
|
dir=$(dirname "$dir")
|
|
42
43
|
done
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
The console script is `eidetic` (dist name: eidetic-cli).
|
|
48
|
-
EOF
|
|
44
|
+
# In a vendored copy there is no eidetic-cli checkout to fall back to, so the
|
|
45
|
+
# only honest remedy is to install the CLI. One `error:` + one `hint:` line.
|
|
46
|
+
printf 'error: eidetic CLI not found.\n' >&2
|
|
47
|
+
printf 'hint: install it with: uv tool install eidetic-cli (or pipx install eidetic-cli); the console script is eidetic.\n' >&2
|
|
49
48
|
return 1
|
|
50
49
|
}
|
|
51
50
|
|
|
@@ -60,7 +59,9 @@ Usage:
|
|
|
60
59
|
|
|
61
60
|
A record needs `id`, `text`, and `type`; `hash` and `metadata` are recommended
|
|
62
61
|
(hash is derived from text when omitted). Upsert is idempotent by id.
|
|
63
|
-
|
|
62
|
+
Records default to this agent's PRIVATE personal scope (--scope from the
|
|
63
|
+
culture.yaml suffix); pass --visibility public to contribute to the shared
|
|
64
|
+
public pool. Every flag is forwarded verbatim to `eidetic remember`.
|
|
64
65
|
See `eidetic explain remember`.
|
|
65
66
|
EOF
|
|
66
67
|
}
|
|
@@ -72,6 +73,16 @@ case "${1:-}" in
|
|
|
72
73
|
;;
|
|
73
74
|
esac
|
|
74
75
|
|
|
76
|
+
# No record argument AND stdin is an interactive terminal → `eidetic remember`
|
|
77
|
+
# would block forever waiting for NDJSON. Show usage instead of hanging. A piped
|
|
78
|
+
# or redirected stdin (`cat records.ndjson | remember.sh`) is not a TTY and
|
|
79
|
+
# proceeds to the batch path normally.
|
|
80
|
+
if [ "$#" -eq 0 ] && [ -t 0 ]; then
|
|
81
|
+
usage >&2
|
|
82
|
+
printf 'hint: pass a JSON record as an argument, or pipe NDJSON on stdin.\n' >&2
|
|
83
|
+
exit 1
|
|
84
|
+
fi
|
|
85
|
+
|
|
75
86
|
resolve_eidetic || exit 2
|
|
76
87
|
|
|
77
88
|
# ── default to this agent's PERSONAL, PRIVATE scope (culture.yaml `suffix`) ──
|
|
@@ -100,9 +111,12 @@ resolve_scope() {
|
|
|
100
111
|
# inline `# comment` or trailing space can't bleed into the scope),
|
|
101
112
|
# then strip surrounding quotes only — matching the canonical parser
|
|
102
113
|
# in .claude/skills/cicd/scripts/_resolve-nick.sh.
|
|
114
|
+
# `|| true`: under `set -o pipefail`, `head -n1` closing the pipe
|
|
115
|
+
# early can SIGPIPE `sed`, making the substitution non-zero and
|
|
116
|
+
# aborting the script. An empty parse must yield "" here, not exit.
|
|
103
117
|
suffix=$(sed -n \
|
|
104
118
|
's/^[[:space:]]*-\{0,1\}[[:space:]]*suffix:[[:space:]]*\([^[:space:]]*\).*/\1/p' \
|
|
105
|
-
"$dir/culture.yaml" | head -n1 | tr -d "\"'")
|
|
119
|
+
"$dir/culture.yaml" | head -n1 | tr -d "\"'" || true)
|
|
106
120
|
break
|
|
107
121
|
fi
|
|
108
122
|
dir=$(dirname "$dir")
|
|
@@ -127,7 +141,19 @@ if ! has_flag --scope "$@"; then
|
|
|
127
141
|
EIDETIC_SCOPE=$(resolve_scope)
|
|
128
142
|
if [ -n "$EIDETIC_SCOPE" ]; then
|
|
129
143
|
SCOPE_ARGS+=(--scope "$EIDETIC_SCOPE")
|
|
130
|
-
|
|
144
|
+
# rollout-cli eidetic-memory recipe POLICY OVERRIDE (not eidetic's
|
|
145
|
+
# upstream private default): default to PUBLIC so a plain remember lands
|
|
146
|
+
# in <repo>/.eidetic/memory — committed, team- and mesh-shared. Pass
|
|
147
|
+
# --visibility private to keep a record in $HOME (uncommitted).
|
|
148
|
+
has_flag --visibility "$@" || SCOPE_ARGS+=(--visibility public)
|
|
149
|
+
elif ! has_flag --visibility "$@"; then
|
|
150
|
+
# No suffix AND no explicit --visibility: the record falls back to
|
|
151
|
+
# eidetic's own default (scope=default, visibility=public). Don't let an
|
|
152
|
+
# expected-private record go public silently — warn on stderr (stdout
|
|
153
|
+
# stays clean for --json). Warn ONLY here: an explicit --scope (outer
|
|
154
|
+
# guard) or --visibility (this guard) means the caller chose deliberately
|
|
155
|
+
# and is honored verbatim, so either flag silences this.
|
|
156
|
+
printf 'warning: no culture.yaml suffix resolved; this record falls back to the public default scope. Pass --scope or --visibility to place it deliberately.\n' >&2
|
|
131
157
|
fi
|
|
132
158
|
fi
|
|
133
159
|
|