context-guard-cli 2.1.0__tar.gz → 2.4.0__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.
Files changed (84) hide show
  1. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/.github/workflows/ci.yml +6 -2
  2. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/CHANGELOG.md +85 -0
  3. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/PKG-INFO +67 -6
  4. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/README.es.md +68 -2
  5. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/README.md +66 -5
  6. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/TUTORIAL.es.md +45 -7
  7. context_guard_cli-2.4.0/context_guard/_data/hosts/antigravity/skills/context-guard/SKILL.md +60 -0
  8. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/_data/phases/plan.md +7 -2
  9. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/guard/cli.py +15 -1
  10. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/guard/commands.py +73 -0
  11. context_guard_cli-2.4.0/context_guard/guard/plan_import.py +253 -0
  12. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/guard/setup.py +113 -26
  13. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/docs/adapters/VERIFY.md +21 -11
  14. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/pyproject.toml +1 -1
  15. context_guard_cli-2.4.0/tests/fixtures/plan_en.md +50 -0
  16. context_guard_cli-2.4.0/tests/fixtures/plan_es.md +60 -0
  17. context_guard_cli-2.4.0/tests/fixtures/plan_no_phases.md +12 -0
  18. context_guard_cli-2.4.0/tests/fixtures/plan_sentinel.md +19 -0
  19. context_guard_cli-2.4.0/tests/fixtures/plan_sparse.md +16 -0
  20. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_adapters.py +5 -4
  21. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_assets.py +77 -0
  22. context_guard_cli-2.4.0/tests/test_from_plan.py +262 -0
  23. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_packaging.py +18 -4
  24. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_phase_docs.py +41 -0
  25. context_guard_cli-2.4.0/tests/test_plan_import.py +202 -0
  26. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_readme.py +20 -0
  27. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_release.py +55 -6
  28. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_setup.py +292 -0
  29. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/.agents/rules/context-guard.md +0 -0
  30. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/.githooks/pre-commit +0 -0
  31. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/.github/workflows/publish.yml +0 -0
  32. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/.gitignore +0 -0
  33. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/AGENTS.md +0 -0
  34. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/LICENSE +0 -0
  35. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/__init__.py +0 -0
  36. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/_data/hosts/antigravity/hooks.snippet.json +0 -0
  37. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/_data/hosts/antigravity/rules/context-guard.md +0 -0
  38. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/_data/hosts/claude-code/commands/cg-continue.md +0 -0
  39. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/_data/hosts/claude-code/commands/cg-new.md +0 -0
  40. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/_data/hosts/claude-code/mcp.snippet.json +0 -0
  41. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/_data/hosts/claude-code/settings.snippet.json +0 -0
  42. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/_data/hosts/opencode/agent.snippet.json +0 -0
  43. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/_data/hosts/opencode/commands/cg-continue.md +0 -0
  44. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/_data/hosts/opencode/commands/cg-new.md +0 -0
  45. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/_data/hosts/opencode/mcp.snippet.json +0 -0
  46. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/_data/hosts/opencode/permissions.snippet.json +0 -0
  47. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/_data/phases/execute.md +0 -0
  48. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/_data/phases/verify.md +0 -0
  49. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/guard/__init__.py +0 -0
  50. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/guard/assets.py +0 -0
  51. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/guard/errors.py +0 -0
  52. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/guard/locking.py +0 -0
  53. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/guard/manifest.py +0 -0
  54. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/guard/migrate.py +0 -0
  55. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/guard/paths.py +0 -0
  56. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/guard/transaction.py +0 -0
  57. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/context_guard/mcp_server.py +0 -0
  58. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/docs/adapters/antigravity/PERMISSIONS.md +0 -0
  59. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/docs/adapters/claude-code/PERMISSIONS.md +0 -0
  60. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/docs/adapters/opencode/PERMISSIONS.md +0 -0
  61. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/__init__.py +0 -0
  62. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_adversarial.py +0 -0
  63. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_adversarial_approve.py +0 -0
  64. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_adversarial_migrate.py +0 -0
  65. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_adversarial_multichange.py +0 -0
  66. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_agents_md.py +0 -0
  67. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_archive.py +0 -0
  68. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_check_completion.py +0 -0
  69. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_commands.py +0 -0
  70. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_doctor.py +0 -0
  71. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_ergonomics.py +0 -0
  72. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_json_format.py +0 -0
  73. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_license.py +0 -0
  74. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_locking.py +0 -0
  75. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_manifest.py +0 -0
  76. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_mcp_server.py +0 -0
  77. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_next_task_status.py +0 -0
  78. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_phases.py +0 -0
  79. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_pre_commit_hook.py +0 -0
  80. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_publish.py +0 -0
  81. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_pyproject_pin.py +0 -0
  82. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_readme_es.py +0 -0
  83. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_transaction.py +0 -0
  84. {context_guard_cli-2.1.0 → context_guard_cli-2.4.0}/tests/test_validate.py +0 -0
@@ -1,10 +1,14 @@
1
1
  name: CI
2
2
 
3
+ # The push list is a pattern, not an enumeration: cycle branches follow vX.Y
4
+ # and the old explicit list went stale silently — v2.5 got no CI on push, only
5
+ # once its PR opened. On pull_request the filter matches the *base* branch, so
6
+ # main alone covers every PR into it.
3
7
  on:
4
8
  push:
5
- branches: [main, v2, v2.1]
9
+ branches: [main, 'v[0-9]*']
6
10
  pull_request:
7
- branches: [main, v2, v2.1]
11
+ branches: [main]
8
12
 
9
13
  jobs:
10
14
  test:
@@ -6,6 +6,91 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
 
7
7
  ---
8
8
 
9
+ ## [2.4.0] - 2026-08-06
10
+
11
+ The bridge between a plan and a change was copy-paste. A phased `PLAN-N.md`
12
+ already holds what `cg new` leaves as `[PENDING]`; now the tool reads it.
13
+
14
+ ### Added
15
+
16
+ - `cg new <name> --from-plan <file>` imports a phased `PLAN-N.md`, creating
17
+ one change per `## F<N>` phase (`<name>-f1`, `<name>-f2`, …). Each phase's
18
+ prose and spec become `objective.md`; its test items and acceptance
19
+ criteria become `tasks.md` in the `- [ ] N.M <text>` form `next-task`
20
+ already parses. `--phase F2` imports one phase. `snapshot.md` stays
21
+ `[PENDING]` — it records the repository state at start, which no plan
22
+ written beforehand can know.
23
+ - `context_guard/guard/plan_import.py`: `parse_plan()` reads a plan into
24
+ title, one-sentence objective, and phases. Headings delimit phases;
25
+ `**Spec:**`, `**Tests:**` and `**Acceptance criteria:**` sub-blocks are
26
+ recognized in English and Spanish. A missing sub-block is empty, not an
27
+ error; a file with no phase heading is `FAIL|PLAN_NO_PHASES|<path>`.
28
+ Parsed with `re` alone — no new dependencies.
29
+ - Changes imported from a plan carry no approval. `cg commit --next-phase
30
+ EXECUTE` still exits 6 until a human runs `cg approve`, once per phase.
31
+ Covered by an adversarial test: a pre-written objective is not a reviewed
32
+ one.
33
+ - Re-importing skips changes that already exist
34
+ (`SKIP|CHANGE_EXISTS|<name>`) instead of overwriting work in flight.
35
+ - A plan quoting the scaffold sentinel `[PENDING]` in its own prose — any
36
+ plan about context-guard itself — would have produced a change the
37
+ PLAN→EXECUTE gate refuses as unfilled, stuck before the approval gate was
38
+ ever reached. The brackets are stripped on import and the substitution is
39
+ reported (`NOTE|SENTINEL_NEUTRALIZED|<change>|<file>`). Fixed on the
40
+ import side deliberately: the artifact really was filled, so loosening the
41
+ gate would have loosened it for every change, imported or not.
42
+
43
+ ## [2.2.0] - 2026-08-02
44
+
45
+ Triggered by real dogfooding: Antigravity never raised the context-guard
46
+ protocol in a fresh project, because `cg setup` only installed its
47
+ enforcement hook, nothing discoverable.
48
+
49
+ ### Added
50
+
51
+ - A discovery skill for Antigravity, installed by `cg setup` at
52
+ `~/.gemini/antigravity-cli/skills/context-guard/SKILL.md` alongside the existing
53
+ deny hook. Antigravity loads skills by progressive disclosure — only the
54
+ name and description sit in context until the model picks it — which is
55
+ what makes this affordable without repeating 2.0's bug 6.0.4
56
+ (`~/.gemini/GEMINI.md` contamination of every project on the machine,
57
+ which stays permanently out of scope). The skill carries the three-phase
58
+ DAG, the operative `cg` commands, and marks `cg approve` human-only.
59
+ - `cg setup --project <dir>` now installs the Antigravity workspace rule
60
+ directly, instead of that artifact only ever being written by `cg new`.
61
+ - A shared ownership-marker check: a skill or rule file not written by
62
+ context-guard is never overwritten — reported as `SKIP|SKILL_EXISTS|<path>`
63
+ and left alone, whether hit through `cg setup` or `cg new`.
64
+
65
+ ### Fixed
66
+
67
+ - Antigravity detection now checks for `agy` — the CLI's actual binary name
68
+ — and `~/.gemini/antigravity-cli`, its state directory. The prior check
69
+ named `antigravity`, which resolves on PATH to an unrelated program.
70
+ - `cg setup --project` was overwriting an `.agents/rules/context-guard.md`
71
+ a team had edited; `cg new` never did. Both paths now honor the same
72
+ ownership marker.
73
+
74
+ ### Changed
75
+
76
+ - README.md, README.es.md and TUTORIAL.es.md Install sections lead with
77
+ `uv tool install context-guard-cli` / `pipx install`, isolated installs
78
+ that land `cg` on PATH globally — what a once-per-machine `cg setup`
79
+ assumes. `pip install` remains documented as a fallback. Explicit warning
80
+ added against `uv pip install context-guard-cli`, which installs into
81
+ whichever project venv is active rather than the machine, silently
82
+ defeating a global `cg setup`.
83
+ - `docs/adapters/VERIFY.md`: step 2 no longer checks Antigravity discovery
84
+ via `agy inspect`, which does not exist as a subcommand — replaced with
85
+ the actual verification, behavioral: a new session, a multi-step task,
86
+ and whether the agent invokes `cg` unprompted. Step 5 no longer names
87
+ `--with-antigravity-hook`, a flag removed in 2.1; the deny hook installs
88
+ by default now, declined with `--no-hooks`.
89
+ - VERIFY.md is complete for all three hosts — Claude Code, OpenCode and
90
+ Antigravity — closing the gap the README used to admit openly. The line
91
+ stating the OpenCode and Antigravity adapters had not been run against a
92
+ live host is removed; both have been.
93
+
9
94
  ## [2.1.0] - 2026-08-01
10
95
 
11
96
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: context-guard-cli
3
- Version: 2.1.0
3
+ Version: 2.4.0
4
4
  Summary: The transactional memory layer for AI coding agents — your context survives crashes, compaction, and session loss
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -82,10 +82,19 @@ illustrative shorthand.
82
82
  Two lines, once per machine:
83
83
 
84
84
  ```bash
85
- pip install context-guard-cli
85
+ uv tool install context-guard-cli
86
86
  cg setup
87
87
  ```
88
88
 
89
+ No `uv`? `pipx install context-guard-cli` works the same way. Both install
90
+ into an isolated environment and put `cg` on PATH globally — the whole point,
91
+ since `cg setup` configures your machine once, not once per project.
92
+ `pip install context-guard-cli` also works, as a fallback for a plain Python
93
+ install with no `uv`/`pipx` available. **Do not use `uv pip install
94
+ context-guard-cli`**: that installs into whichever venv is currently active —
95
+ a single project's, if you happen to be inside one — not onto the machine,
96
+ which silently defeats the point of a global `cg setup`.
97
+
89
98
  `cg setup` detects Claude Code, OpenCode and Antigravity, installs the slash
90
99
  commands, and puts `cg approve` behind each one's permission prompt — see
91
100
  [Adapters](#adapters-and-permission-configuration). It prints every file it
@@ -106,6 +115,22 @@ cd context-guard && uv venv && uv pip install -e ".[dev]"
106
115
  git config core.hooksPath .githooks # activates the pre-commit gate below
107
116
  ```
108
117
 
118
+ ## Upgrading
119
+
120
+ ```bash
121
+ uv tool upgrade context-guard-cli && cg setup
122
+ ```
123
+
124
+ The second command is not optional. `cg setup` copies commands, skills and
125
+ permission snippets into your host configs; upgrading the package does not
126
+ touch those copies, so a new version's adapter fixes only reach a machine
127
+ once `cg setup` runs again. It is idempotent — safe to run any time.
128
+
129
+ Phase files already materialised in a project (`.context-guard/phases/`)
130
+ are never overwritten, by design: a project keeps the phases it was started
131
+ with, including your edits. Delete a phase file and run `cg new` to pull the
132
+ current version.
133
+
109
134
  ## How it works
110
135
 
111
136
  ```
@@ -176,6 +201,7 @@ unconditional block just gets `--no-verify`d, which leaves no trace at all.
176
201
  | Command | Purpose |
177
202
  |---|---|
178
203
  | `cg new <name> --context <path>` | Create a change and begin PLAN |
204
+ | `cg new <name> --from-plan <file> [--phase F2]` | Import a phased `PLAN-N.md` as one change per phase |
179
205
  | `cg list --context <path>` | List active changes and their phase |
180
206
  | `cg begin --phase <PHASE> --context <path>` | Start a transaction for the given phase |
181
207
  | `cg approve [--by <who>] [--hotfix --reason "<text>"]` | Human-only: record the sign-off `commit` into EXECUTE requires |
@@ -218,6 +244,36 @@ shows what is active; `cg archive` moves a finished one to
218
244
  `state.ini` and context-guard 1.x's flat `.context-guard/` — in place and
219
245
  idempotently, preserving any recorded human approval it finds.
220
246
 
247
+ ## From a phased plan
248
+
249
+ If a cycle was already planned as a phased `PLAN-N.md` — the artifact
250
+ [disciplined-scaffold](https://github.com/fdomerlo/disciplined-scaffold)
251
+ produces after you talk a project through with an assistant — `cg new
252
+ --from-plan` materialises it instead of you retyping it:
253
+
254
+ ```bash
255
+ cg new redis --from-plan PLAN-3.md
256
+ ```
257
+
258
+ One change per `## F<N>` phase, named `redis-f1`, `redis-f2`, … Each phase's
259
+ prose and spec become its `objective.md`; its test items and acceptance
260
+ criteria become `tasks.md` as `- [ ] N.M <text>`, the shape `cg next-task`
261
+ already claims. `--phase F2` imports a single phase. Re-running skips changes
262
+ that already exist (`SKIP|CHANGE_EXISTS|<name>`) rather than overwriting work
263
+ in flight.
264
+
265
+ `snapshot.md` stays `[PENDING]`: it records the state of the repository when
266
+ work starts, which no plan written beforehand can know.
267
+
268
+ **Importing does not approve anything.** Each change lands in PLAN with no
269
+ approval in its manifest, so `cg commit --next-phase EXECUTE` still exits 6
270
+ until a human runs `cg approve` — once per phase. A pre-written objective is
271
+ still an unreviewed one.
272
+
273
+ The full flow: talk the project through → `disciplined-scaffold` writes
274
+ `PLAN-N.md` → `cg new --from-plan` → each phase executes under the same
275
+ approval gate as any other change.
276
+
221
277
  ## Pre-commit hook
222
278
 
223
279
  `.githooks/pre-commit` rejects commits touching more than a threshold number
@@ -256,9 +312,7 @@ at `phases/{plan,execute,verify}.md` rather than duplicating them. How to put
256
312
  `cg approve` behind each harness's permission prompt is documented in
257
313
  [docs/adapters/](docs/adapters/), one `PERMISSIONS.md` per host, alongside the
258
314
  manual smoke-test checklist in [docs/adapters/VERIFY.md](docs/adapters/VERIFY.md).
259
- `cg setup` installs the right one for each detected host. The OpenCode and Antigravity
260
- adapters are ported from state-guard and covered by static tests only — they
261
- have not been run against a live host of either.
315
+ `cg setup` installs the right one for each detected host.
262
316
 
263
317
  ## How this compares
264
318
 
@@ -279,6 +333,11 @@ turning a prompt into a good spec in the first place. Use context-guard
279
333
  together with whichever of them already generates your `objective.md` — it
280
334
  was designed to consume one, not to write one.
281
335
 
336
+ [disciplined-scaffold](https://github.com/fdomerlo/disciplined-scaffold) is
337
+ the lighter step before this one: markdown-only phase discipline, no
338
+ transactional state. When a project outgrows it, `cg new --from-plan` reads
339
+ the `PLAN-N.md` it produced — see [From a phased plan](#from-a-phased-plan).
340
+
282
341
  ## Development
283
342
 
284
343
  ```bash
@@ -289,7 +348,9 @@ python -m unittest discover -s tests
289
348
 
290
349
  Framework: `unittest`. Every fix ships with an adversarial test that
291
350
  reproduces the bypass it closes; see `tests/test_adversarial_*.py` for the
292
- pattern. No fixtures on disk outside `tempfile.mkdtemp()`.
351
+ pattern. Tests write only under `tempfile.mkdtemp()`; the sole read-only
352
+ fixtures on disk are the sample plans in `tests/fixtures/`, which exist
353
+ because `--from-plan` parses documents rather than generating them.
293
354
 
294
355
  ## License
295
356
 
@@ -66,10 +66,20 @@ nada acá es un resumen ilustrativo.
66
66
  Dos líneas, una vez por máquina:
67
67
 
68
68
  ```bash
69
- pip install context-guard-cli
69
+ uv tool install context-guard-cli
70
70
  cg setup
71
71
  ```
72
72
 
73
+ ¿No tenés `uv`? `pipx install context-guard-cli` hace lo mismo. Ambos
74
+ instalan en un entorno aislado y dejan `cg` en el PATH global — que es el
75
+ punto, porque `cg setup` configura tu máquina una vez, no una vez por
76
+ proyecto. `pip install context-guard-cli` también funciona, como alternativa
77
+ para una instalación de Python simple sin `uv`/`pipx` disponible. **No uses
78
+ `uv pip install context-guard-cli`**: eso instala en el venv que esté activo
79
+ en ese momento — el de un proyecto puntual, si estás parado adentro de
80
+ uno — no en la máquina, lo que anula en silencio el sentido de un `cg setup`
81
+ global.
82
+
73
83
  `cg setup` detecta Claude Code, OpenCode y Antigravity, instala los slash
74
84
  commands, y deja `cg approve` detrás del permission prompt de cada uno — ver
75
85
  [Adapters](#adapters-y-configuración-de-permisos). Imprime cada archivo que
@@ -91,6 +101,23 @@ cd context-guard && uv venv && uv pip install -e ".[dev]"
91
101
  git config core.hooksPath .githooks # activa el gate de pre-commit de más abajo
92
102
  ```
93
103
 
104
+ ## Actualizar
105
+
106
+ ```bash
107
+ uv tool upgrade context-guard-cli && cg setup
108
+ ```
109
+
110
+ El segundo comando no es opcional. `cg setup` copia los comandos, skills y
111
+ snippets de permisos dentro de la configuración de tus hosts; actualizar el
112
+ paquete no toca esas copias, así que las correcciones de adapters de una
113
+ versión nueva recién llegan a la máquina cuando se vuelve a correr
114
+ `cg setup`. Es idempotente — se puede correr las veces que quieras.
115
+
116
+ Las fases ya materializadas en un proyecto (`.context-guard/phases/`) nunca
117
+ se sobrescriben, por diseño: cada proyecto conserva las fases con las que
118
+ empezó, incluidas tus ediciones. Borrá el archivo de fase y corré `cg new`
119
+ para traer la versión actual.
120
+
94
121
  ## Cómo funciona
95
122
 
96
123
  ```
@@ -163,6 +190,7 @@ garantía de corrección, y viene con un bypass auditado
163
190
  | Comando | Propósito |
164
191
  |---|---|
165
192
  | `cg new <nombre> --context <ruta>` | Crea un change y arranca PLAN |
193
+ | `cg new <nombre> --from-plan <archivo> [--phase F2]` | Importa un `PLAN-N.md` por fases como un change por fase |
166
194
  | `cg list --context <ruta>` | Lista los changes activos y su fase |
167
195
  | `cg begin --phase <FASE> --context <ruta>` | Inicia una transacción para la fase dada |
168
196
  | `cg approve [--by <quién>] [--hotfix --reason "<texto>"]` | Solo humano: registra el visto bueno que `commit` exige para entrar a EXECUTE |
@@ -206,6 +234,36 @@ de forma independiente en el mismo proyecto. `cg new <nombre>` crea uno;
206
234
  1.x — in situ y de forma idempotente, preservando cualquier aprobación
207
235
  humana registrada que encuentre.
208
236
 
237
+ ## Desde un plan por fases
238
+
239
+ Si el ciclo ya se planificó como un `PLAN-N.md` por fases — el artefacto que
240
+ produce [disciplined-scaffold](https://github.com/fdomerlo/disciplined-scaffold)
241
+ después de debatir un proyecto con el asistente — `cg new --from-plan` lo
242
+ materializa en vez de que lo retipees:
243
+
244
+ ```bash
245
+ cg new redis --from-plan PLAN-3.md
246
+ ```
247
+
248
+ Un change por cada fase `## F<N>`, nombrados `redis-f1`, `redis-f2`, … La
249
+ prosa y el spec de cada fase se vuelven su `objective.md`; sus ítems de test
250
+ y criterios de aceptación se vuelven `tasks.md` en formato `- [ ] N.M
251
+ <texto>`, el que `cg next-task` ya reclama. `--phase F2` importa una sola
252
+ fase. Re-ejecutar saltea los changes que ya existen
253
+ (`SKIP|CHANGE_EXISTS|<nombre>`) en vez de pisar trabajo en curso.
254
+
255
+ `snapshot.md` queda `[PENDING]`: registra el estado del repositorio al
256
+ arrancar, que ningún plan escrito de antemano puede conocer.
257
+
258
+ **Importar no aprueba nada.** Cada change entra en PLAN sin aprobación en su
259
+ manifest, así que `cg commit --next-phase EXECUTE` sigue saliendo con código
260
+ 6 hasta que un humano corra `cg approve` — una vez por fase. Un objetivo
261
+ pre-escrito sigue siendo un objetivo sin revisar.
262
+
263
+ El flujo completo: debatir el proyecto → `disciplined-scaffold` escribe
264
+ `PLAN-N.md` → `cg new --from-plan` → cada fase se ejecuta bajo el mismo gate
265
+ de aprobación que cualquier otro change.
266
+
209
267
  ## Hook de pre-commit
210
268
 
211
269
  `.githooks/pre-commit` rechaza commits que tocan más de un umbral de
@@ -269,6 +327,11 @@ lo referido a convertir un prompt en un buen spec en primer lugar. Usá
269
327
  context-guard junto con cualquiera de ellos que ya te genere el
270
328
  `objective.md` — está diseñado para consumir uno, no para escribirlo.
271
329
 
330
+ [disciplined-scaffold](https://github.com/fdomerlo/disciplined-scaffold) es
331
+ el paso liviano previo a este: disciplina de fases en markdown, sin estado
332
+ transaccional. Cuando un proyecto lo supera, `cg new --from-plan` lee el
333
+ `PLAN-N.md` que produjo — ver [Desde un plan por fases](#desde-un-plan-por-fases).
334
+
272
335
  ## Desarrollo
273
336
 
274
337
  ```bash
@@ -279,7 +342,10 @@ python -m unittest discover -s tests
279
342
 
280
343
  Framework: `unittest`. Cada fix se entrega con un test adversarial que
281
344
  reproduce el bypass que cierra; ver `tests/test_adversarial_*.py` para el
282
- patrón. Sin fixtures en disco fuera de `tempfile.mkdtemp()`.
345
+ patrón. Los tests solo escriben bajo `tempfile.mkdtemp()`; los únicos
346
+ fixtures en disco son los planes de ejemplo de solo lectura en
347
+ `tests/fixtures/`, que existen porque `--from-plan` parsea documentos en vez
348
+ de generarlos.
283
349
 
284
350
  ## Licencia
285
351
 
@@ -69,10 +69,19 @@ illustrative shorthand.
69
69
  Two lines, once per machine:
70
70
 
71
71
  ```bash
72
- pip install context-guard-cli
72
+ uv tool install context-guard-cli
73
73
  cg setup
74
74
  ```
75
75
 
76
+ No `uv`? `pipx install context-guard-cli` works the same way. Both install
77
+ into an isolated environment and put `cg` on PATH globally — the whole point,
78
+ since `cg setup` configures your machine once, not once per project.
79
+ `pip install context-guard-cli` also works, as a fallback for a plain Python
80
+ install with no `uv`/`pipx` available. **Do not use `uv pip install
81
+ context-guard-cli`**: that installs into whichever venv is currently active —
82
+ a single project's, if you happen to be inside one — not onto the machine,
83
+ which silently defeats the point of a global `cg setup`.
84
+
76
85
  `cg setup` detects Claude Code, OpenCode and Antigravity, installs the slash
77
86
  commands, and puts `cg approve` behind each one's permission prompt — see
78
87
  [Adapters](#adapters-and-permission-configuration). It prints every file it
@@ -93,6 +102,22 @@ cd context-guard && uv venv && uv pip install -e ".[dev]"
93
102
  git config core.hooksPath .githooks # activates the pre-commit gate below
94
103
  ```
95
104
 
105
+ ## Upgrading
106
+
107
+ ```bash
108
+ uv tool upgrade context-guard-cli && cg setup
109
+ ```
110
+
111
+ The second command is not optional. `cg setup` copies commands, skills and
112
+ permission snippets into your host configs; upgrading the package does not
113
+ touch those copies, so a new version's adapter fixes only reach a machine
114
+ once `cg setup` runs again. It is idempotent — safe to run any time.
115
+
116
+ Phase files already materialised in a project (`.context-guard/phases/`)
117
+ are never overwritten, by design: a project keeps the phases it was started
118
+ with, including your edits. Delete a phase file and run `cg new` to pull the
119
+ current version.
120
+
96
121
  ## How it works
97
122
 
98
123
  ```
@@ -163,6 +188,7 @@ unconditional block just gets `--no-verify`d, which leaves no trace at all.
163
188
  | Command | Purpose |
164
189
  |---|---|
165
190
  | `cg new <name> --context <path>` | Create a change and begin PLAN |
191
+ | `cg new <name> --from-plan <file> [--phase F2]` | Import a phased `PLAN-N.md` as one change per phase |
166
192
  | `cg list --context <path>` | List active changes and their phase |
167
193
  | `cg begin --phase <PHASE> --context <path>` | Start a transaction for the given phase |
168
194
  | `cg approve [--by <who>] [--hotfix --reason "<text>"]` | Human-only: record the sign-off `commit` into EXECUTE requires |
@@ -205,6 +231,36 @@ shows what is active; `cg archive` moves a finished one to
205
231
  `state.ini` and context-guard 1.x's flat `.context-guard/` — in place and
206
232
  idempotently, preserving any recorded human approval it finds.
207
233
 
234
+ ## From a phased plan
235
+
236
+ If a cycle was already planned as a phased `PLAN-N.md` — the artifact
237
+ [disciplined-scaffold](https://github.com/fdomerlo/disciplined-scaffold)
238
+ produces after you talk a project through with an assistant — `cg new
239
+ --from-plan` materialises it instead of you retyping it:
240
+
241
+ ```bash
242
+ cg new redis --from-plan PLAN-3.md
243
+ ```
244
+
245
+ One change per `## F<N>` phase, named `redis-f1`, `redis-f2`, … Each phase's
246
+ prose and spec become its `objective.md`; its test items and acceptance
247
+ criteria become `tasks.md` as `- [ ] N.M <text>`, the shape `cg next-task`
248
+ already claims. `--phase F2` imports a single phase. Re-running skips changes
249
+ that already exist (`SKIP|CHANGE_EXISTS|<name>`) rather than overwriting work
250
+ in flight.
251
+
252
+ `snapshot.md` stays `[PENDING]`: it records the state of the repository when
253
+ work starts, which no plan written beforehand can know.
254
+
255
+ **Importing does not approve anything.** Each change lands in PLAN with no
256
+ approval in its manifest, so `cg commit --next-phase EXECUTE` still exits 6
257
+ until a human runs `cg approve` — once per phase. A pre-written objective is
258
+ still an unreviewed one.
259
+
260
+ The full flow: talk the project through → `disciplined-scaffold` writes
261
+ `PLAN-N.md` → `cg new --from-plan` → each phase executes under the same
262
+ approval gate as any other change.
263
+
208
264
  ## Pre-commit hook
209
265
 
210
266
  `.githooks/pre-commit` rejects commits touching more than a threshold number
@@ -243,9 +299,7 @@ at `phases/{plan,execute,verify}.md` rather than duplicating them. How to put
243
299
  `cg approve` behind each harness's permission prompt is documented in
244
300
  [docs/adapters/](docs/adapters/), one `PERMISSIONS.md` per host, alongside the
245
301
  manual smoke-test checklist in [docs/adapters/VERIFY.md](docs/adapters/VERIFY.md).
246
- `cg setup` installs the right one for each detected host. The OpenCode and Antigravity
247
- adapters are ported from state-guard and covered by static tests only — they
248
- have not been run against a live host of either.
302
+ `cg setup` installs the right one for each detected host.
249
303
 
250
304
  ## How this compares
251
305
 
@@ -266,6 +320,11 @@ turning a prompt into a good spec in the first place. Use context-guard
266
320
  together with whichever of them already generates your `objective.md` — it
267
321
  was designed to consume one, not to write one.
268
322
 
323
+ [disciplined-scaffold](https://github.com/fdomerlo/disciplined-scaffold) is
324
+ the lighter step before this one: markdown-only phase discipline, no
325
+ transactional state. When a project outgrows it, `cg new --from-plan` reads
326
+ the `PLAN-N.md` it produced — see [From a phased plan](#from-a-phased-plan).
327
+
269
328
  ## Development
270
329
 
271
330
  ```bash
@@ -276,7 +335,9 @@ python -m unittest discover -s tests
276
335
 
277
336
  Framework: `unittest`. Every fix ships with an adversarial test that
278
337
  reproduces the bypass it closes; see `tests/test_adversarial_*.py` for the
279
- pattern. No fixtures on disk outside `tempfile.mkdtemp()`.
338
+ pattern. Tests write only under `tempfile.mkdtemp()`; the sole read-only
339
+ fixtures on disk are the sample plans in `tests/fixtures/`, which exist
340
+ because `--from-plan` parses documents rather than generating them.
280
341
 
281
342
  ## License
282
343
 
@@ -37,7 +37,7 @@ Una aclaración honesta, porque este proyecto se toma en serio la honestidad: co
37
37
  Abrí la terminal y corré:
38
38
 
39
39
  ```bash
40
- pip install context-guard-cli
40
+ uv tool install context-guard-cli
41
41
  cg setup
42
42
  ```
43
43
 
@@ -48,8 +48,14 @@ aprobación (paso 4). Al terminar imprime la lista exacta de archivos que
48
48
  tocó — nada oculto. Podés correrlo las veces que quieras: si ya está
49
49
  instalado, no duplica nada.
50
50
 
51
- *(Si usás `uv`, que es más rápido: `uv tool install context-guard-cli` y
52
- después `cg setup`.)*
51
+ ¿No tenés `uv`? `pipx install context-guard-cli` hace lo mismo. Si ninguno de
52
+ los dos está disponible, `pip install context-guard-cli` también funciona,
53
+ como alternativa.
54
+
55
+ > **Ojo con esta:** `uv pip install context-guard-cli` *no* es lo mismo que
56
+ > `uv tool install`. Instala la herramienta adentro del entorno virtual de
57
+ > tu proyecto actual, no en tu máquina — y `cg setup` necesita que `cg` esté
58
+ > disponible en cualquier terminal, no solo dentro de ese proyecto.
53
59
 
54
60
  Verificá que quedó todo:
55
61
 
@@ -64,9 +70,40 @@ herramienta; todo lo que hagas con context-guard empieza con `cg`.
64
70
  un cambio en un proyecto nuevo, `cg new` escribe ahí lo que falte. No
65
71
  necesitás descargar este repositorio ni copiar archivos a mano.
66
72
 
67
- > **Si algo falla:** el error más común es que `pip` instaló pero la terminal
68
- > no encuentra `cg`. Cerrá y reabrí la terminal. Si persiste, probá
69
- > `python3 -m pip install --user context-guard-cli` y de nuevo cerrar/reabrir.
73
+ > **¿Dónde quedó instalado?** `uv tool install` y `pipx` ponen `cg` en un
74
+ > directorio propio (`~/.local/bin` en Linux/macOS típicamente) y lo agregan
75
+ > al PATH por vos. `pip install` sin `--user` lo deja donde viva tu Python
76
+ > del sistema; con `--user`, en `~/.local/bin` también. Si el paso de
77
+ > verificación de arriba no encuentra `cg`, es casi siempre esto: el
78
+ > directorio existe pero tu terminal no lo tiene en el PATH todavía.
79
+
80
+ > **Si algo falla:** el error más común es que la instalación terminó bien
81
+ > pero la terminal no encuentra `cg`. Cerrá y reabrí la terminal. Si
82
+ > persiste, probá `python3 -m pip install --user context-guard-cli` y de
83
+ > nuevo cerrar/reabrir.
84
+
85
+ ---
86
+
87
+ ## 3.1. Cómo actualizar
88
+
89
+ Cuando salga una versión nueva, dos comandos en uno:
90
+
91
+ ```bash
92
+ uv tool upgrade context-guard-cli && cg setup
93
+ ```
94
+
95
+ *(Con pipx: `pipx upgrade context-guard-cli && cg setup`.)*
96
+
97
+ **Por qué son dos y no uno:** el primero actualiza el programa; el segundo
98
+ vuelve a copiar los comandos y la configuración dentro de tu asistente. Si
99
+ hacés solo el primero, tu asistente sigue usando las instrucciones viejas y
100
+ las mejoras de la versión nueva no aparecen. Correr `cg setup` de más nunca
101
+ rompe nada.
102
+
103
+ **Tus proyectos viejos siguen como estaban.** Las guías de fase que se
104
+ copiaron dentro de cada proyecto no se pisan al actualizar — a propósito,
105
+ para no borrar cambios que hayas hecho. Los proyectos nuevos arrancan con
106
+ las guías actualizadas.
70
107
 
71
108
  ---
72
109
 
@@ -172,7 +209,8 @@ Diagnostica y libera lo que quedó colgado de procesos muertos. Nunca resuelvas
172
209
  | Ver el avance | `cg status` | — |
173
210
  | Retomar tras un corte | `/cg-continue` | Continúa donde quedó |
174
211
  | Destrabar | `cg doctor --fix` | — |
212
+ | Actualizar | `uv tool upgrade context-guard-cli && cg setup` | — |
175
213
 
176
- Instalación (una vez): `pip install context-guard-cli` y luego `cg setup` una vez por máquina.
214
+ Instalación (una vez): `uv tool install context-guard-cli` y luego `cg setup` una vez por máquina.
177
215
 
178
216
  Documentación completa, en inglés y español, en el [repositorio](https://github.com/fdomerlo/context-guard).
@@ -0,0 +1,60 @@
1
+ ---
2
+ name: context-guard
3
+ description: >-
4
+ Use when the user asks to build, implement, or scaffold an application or
5
+ feature; for any multi-step coding task; to resume work after a lost,
6
+ crashed or compacted session; or in any project that already contains a
7
+ `.context-guard/` directory. Drives the `cg` CLI so a phase-governed change
8
+ keeps its plan, its progress and its verification on disk instead of in
9
+ the conversation.
10
+ ---
11
+
12
+ <!-- context-guard:begin -->
13
+ # context-guard
14
+
15
+ `cg` (long form: `context-guard`) is a transactional state manager. A change
16
+ moves through fixed phases and nothing advances without passing that phase's
17
+ gate, so a session that dies mid-task resumes instead of restarting.
18
+
19
+ ## The pipeline
20
+
21
+ ```
22
+ PLAN --approve--> EXECUTE --tasks done--> VERIFY --approve--> ARCHIVE
23
+ ```
24
+
25
+ | Phase | Produces | Gate to leave it |
26
+ |---------|----------------------------------------|-------------------------------|
27
+ | PLAN | `objective.md`, `tasks.md` | human approval, then `commit` |
28
+ | EXECUTE | code changes, `tasks.md` checked off | every task checked off |
29
+ | VERIFY | `review-report.md`, `verify-report.md` | human approval, then archive |
30
+
31
+ `cg commit` rejects any transition outside that order.
32
+
33
+ ## On entering a phase, read that phase's file
34
+
35
+ The full instructions live in `.context-guard/phases/plan.md`,
36
+ `.context-guard/phases/execute.md` and `.context-guard/phases/verify.md` —
37
+ not in this skill. Load the file for the phase you are entering and follow
38
+ it exactly.
39
+
40
+ ## Commands
41
+
42
+ - `cg new <name>` — scaffold a change, open PLAN, write the phase files.
43
+ - `cg status` — what phase the change is in and what is still pending. Run
44
+ this first when resuming, before reading any code.
45
+ - `cg next-task` — the next unchecked task, during EXECUTE.
46
+ - `cg commit --next-phase <PHASE>` — advance, once the gate passes.
47
+ - `cg list`, `cg validate`, `cg checkpoint`, `cg rollback` — inspect, check,
48
+ snapshot, undo.
49
+
50
+ Every command takes `--change <name>`. Pass it whenever more than one change
51
+ is active: `cg` errors rather than guessing which one you meant.
52
+
53
+ ## `cg approve` is human-only
54
+
55
+ Never run `cg approve` yourself, and never run it "on behalf of" the user.
56
+ When `cg commit` exits 6 (`APPROVAL_REQUIRED`), stop, show the human the
57
+ artifacts the gate covers, and ask them to run the approval themselves.
58
+ Editing `.context-guard/**/manifest.json` by hand is the same violation by
59
+ another route: it forges the state the gate reads.
60
+ <!-- context-guard:end -->
@@ -122,8 +122,13 @@ cg commit --context <path> --change <change-name> --next-phase EXECUTE
122
122
  ```
123
123
 
124
124
  This advances `lock_phase` to `EXECUTE`, releases the phase lock, and
125
- auto-generates a checkpoint of the DAG state. Report to the user that PLAN is
126
- locked and EXECUTE is open, with the suggested next command: `/cg-continue`.
125
+ auto-generates a checkpoint of the DAG state.
126
+
127
+ Report to the user that PLAN is locked and EXECUTE is open. Then, in this
128
+ same turn, load `.context-guard/phases/execute.md` and continue directly —
129
+ do not wait for `/cg-continue`. Only stop and suggest `/cg-continue` if you
130
+ are ending the turn for an unrelated reason, or the session might not
131
+ continue (e.g., you are about to hit a context limit).
127
132
 
128
133
  ## Rules
129
134
 
@@ -12,6 +12,7 @@ from .commands import (
12
12
  cmd_approve,
13
13
  cmd_check_lock,
14
14
  cmd_new,
15
+ cmd_new_from_plan,
15
16
  cmd_setup,
16
17
  cmd_list,
17
18
  cmd_migrate,
@@ -135,6 +136,14 @@ def parse_args(argv=None):
135
136
  help="Also materialise this host's workspace files "
136
137
  "(Antigravity's rule file). Detected automatically "
137
138
  "when omitted.")
139
+ p_new.add_argument("--from-plan", dest="from_plan", default=None,
140
+ help="Import a phased PLAN-N.md, creating one change "
141
+ "per phase (<name>-f1, <name>-f2, ...) with "
142
+ "objective.md and tasks.md derived from it. The "
143
+ "approval gate is unchanged: each change still "
144
+ "needs cg approve to reach EXECUTE.")
145
+ p_new.add_argument("--phase", default=None,
146
+ help="With --from-plan, import only this phase (e.g. F2).")
138
147
 
139
148
  # setup takes no --context: it configures hosts, not a change. --project
140
149
  # opts back into 2.0's per-project install for teams committing the config.
@@ -180,7 +189,12 @@ def dispatch(args):
180
189
  """
181
190
  change = getattr(args, "change", None)
182
191
  handlers = {
183
- "new": lambda: cmd_new(args.context, args.name, args.host),
192
+ "new": lambda: (
193
+ cmd_new_from_plan(args.context, args.name, args.from_plan,
194
+ phase=args.phase, host=args.host)
195
+ if args.from_plan
196
+ else cmd_new(args.context, args.name, args.host)
197
+ ),
184
198
  "setup": lambda: cmd_setup(
185
199
  host=args.host, with_mcp=args.with_mcp, project=args.project,
186
200
  no_hooks=args.no_hooks),