luciazero 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +423 -0
- package/LICENSE +21 -0
- package/README.md +219 -0
- package/README.th.md +215 -0
- package/bin/luciazero.js +35 -0
- package/claude/agents/reviewer.md +43 -0
- package/claude/hooks/hooks.json +33 -0
- package/claude/hooks/luciazero-statusline.sh +81 -0
- package/claude/hooks/luciazero-verify.sh +252 -0
- package/claude/luciazero.md +24 -0
- package/install-codex.sh +84 -0
- package/install.sh +249 -0
- package/package.json +34 -0
- package/skills/debug/SKILL.md +51 -0
- package/skills/done/SKILL.md +57 -0
- package/skills/done/scripts/revert-probe.sh +95 -0
- package/skills/experiment/SKILL.md +44 -0
- package/skills/handoff/SKILL.md +56 -0
- package/skills/luciazero-bootstrap/SKILL.md +109 -0
- package/skills/luciazero-bootstrap/scripts/detect.sh +84 -0
- package/skills/retro/SKILL.md +74 -0
- package/uninstall-codex.sh +50 -0
- package/uninstall.sh +139 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: luciazero-bootstrap
|
|
3
|
+
description: Make a repository agentic-ready so an agent can run its own plan→change→verify→fix loop without a human checking each step. Use when entering an unfamiliar repo, when the user asks to "set up agentic engineering", "make this repo agent-friendly", "add a verify command", "add smoke tests so you can check your own work", "set up hooks/CLAUDE.md/allowlist" — or when a change was requested but no automated way exists to prove it works.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Luciazero Bootstrap
|
|
7
|
+
|
|
8
|
+
Goal: leave the repo with **one command that returns an exit code** and enough guardrails that future agent work self-verifies. Nothing here is language-specific — detect, don't assume.
|
|
9
|
+
|
|
10
|
+
Bootstrapping is itself work: verify each artifact you add actually runs before reporting it.
|
|
11
|
+
|
|
12
|
+
## Phase 1 — Detect (never assume)
|
|
13
|
+
|
|
14
|
+
Run the bundled evidence scan first — it replaces a dozen manual reads with one call:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
<this-skill-dir>/scripts/detect.sh <repo-root>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
(The skill directory is wherever this SKILL.md lives, e.g. `~/.claude/skills/luciazero-bootstrap/` or `~/.codex/skills/luciazero-bootstrap/`.) The script surfaces candidates — **you still decide**. It cannot parse CI matrices or exotic build systems; open anything it flags and read the CI config yourself.
|
|
21
|
+
|
|
22
|
+
Sources, in order of trust:
|
|
23
|
+
|
|
24
|
+
1. CI config — the most honest source of truth: `.github/workflows/*`, `.gitlab-ci.yml`, `.circleci/`. **Whatever CI runs is the verify command.**
|
|
25
|
+
2. Manifests: `package.json` scripts, `pyproject.toml` / `tox.ini` / `noxfile.py`, `Makefile`, `justfile`, `Cargo.toml`, `go.mod`, `build.gradle`, `composer.json`
|
|
26
|
+
3. Repo docs: `README*`, `CONTRIBUTING*`, `AGENTS.md`, `CLAUDE.md`, `docs/` — docs go stale; cross-check any doc-claimed command against CI when CI exists. A docs/CI mismatch is itself a finding to record in Phase 5.
|
|
27
|
+
4. Existing test dirs: `tests/`, `test/`, `spec/`, `__tests__/`, `*_test.*`, `test_*.*`
|
|
28
|
+
|
|
29
|
+
Report what was found as a short table: run / test / lint / typecheck / build / git repo — command or `MISSING`.
|
|
30
|
+
|
|
31
|
+
**If the directory is not under version control**, propose `git init` early (ask first — some dirs are deliberately not repos): without git there is no smallest reversible step, no safe break-and-restore in Phase 6, and no bisect.
|
|
32
|
+
|
|
33
|
+
## Phase 2 — Establish the verify command
|
|
34
|
+
|
|
35
|
+
If a verify path exists, **use it** — do not invent a parallel one.
|
|
36
|
+
|
|
37
|
+
If none exists, create the smallest real one. Order of preference:
|
|
38
|
+
|
|
39
|
+
1. The project's native runner, already installed (`pytest`, `vitest`, `go test`, `cargo test`, `dotnet test`)
|
|
40
|
+
2. A single entrypoint that chains them, matching the repo's existing convention (`Makefile` target, `package.json` script, `justfile` recipe) — e.g. `make verify` running lint then tests
|
|
41
|
+
|
|
42
|
+
Rules:
|
|
43
|
+
- Must exit non-zero on failure. A script that always exits 0 is worse than nothing.
|
|
44
|
+
- Must run to completion unattended: disable watch/interactive modes (e.g. `CI=1`, `--run`, `--watch=false`) — a command that waits for input or watches files hangs the loop.
|
|
45
|
+
- Must run offline, with no credentials. Anything needing GPU/network/secrets belongs in a separate slow target.
|
|
46
|
+
- Time the suite once (`time <cmd>`); the measurement, not a guess, decides one tier or two.
|
|
47
|
+
- On success, output should be near-silent — prefer quiet flags in the fast tier so failures, not progress spam, fill the context.
|
|
48
|
+
- Add it to the repo's own docs so humans find it too.
|
|
49
|
+
|
|
50
|
+
**Two tiers when the repo has slow checks.** One `verify` command forces a bad trade: either the loop crawls or coverage gets cut. Split it:
|
|
51
|
+
|
|
52
|
+
- `verify` — fast (<~60s), offline: lint, typecheck, unit/smoke tests. Run on **every** loop iteration.
|
|
53
|
+
- `verify-full` — everything else: full suite, integration, build, slow checks. Run **before declaring done** and before a PR — "done" means `verify-full` green, not just `verify`.
|
|
54
|
+
|
|
55
|
+
Name them by the repo's convention (`make verify` / `make verify-full`, npm scripts, just recipes). A small repo whose whole suite runs in seconds needs only the single tier — do not add ceremony it does not need.
|
|
56
|
+
|
|
57
|
+
**Monorepos:** detect the workspace layout (`package.json` `workspaces`, `pnpm-workspace.yaml`, turbo/nx config, `go.work`, Cargo `[workspace]`). The fast tier must be scoped to the package being changed (e.g. `pnpm --filter <pkg> test`, `go test ./changed/pkg/...`, `cargo test -p <crate>`); `verify-full` is the root suite. Record in the Phase 5 notes how to derive the scoped command from a file path.
|
|
58
|
+
|
|
59
|
+
**Enforcement pack users (Claude Code, ask first):** if the verify-tracking hooks are active — classic install: `~/.claude/hooks/luciazero-verify.sh` exists; plugin install: the `luciazero` plugin is enabled — offer to record the established command in the repo's *personal* settings so the tracker matches it exactly instead of by broad regex — `.claude/settings.local.json` (gitignored, never committed): `{"env": {"LUCIAZERO_VERIFY_CMD": "<the fast-tier command>"}}`. Derive it from CI (the honest source); it is a cache of that truth, so note it must be updated if CI changes. Show the exact JSON before writing anything.
|
|
60
|
+
|
|
61
|
+
## Phase 3 — Smoke tests, if there are none
|
|
62
|
+
|
|
63
|
+
Do **not** attempt coverage. Write 3–6 tests that would catch a catastrophic break. Pick by this heuristic:
|
|
64
|
+
|
|
65
|
+
- **Contract shape** — the core data structure in/out: dimensions, keys, types, no NaN/null where impossible
|
|
66
|
+
- **Round trip** — serialize→deserialize, encode→decode, save→load returns equal
|
|
67
|
+
- **Import/boot** — every package imports, the app answers one request, the CLI runs `--help`. Prefer the framework's test client over binding a real port; any test that starts a process needs a hard timeout and must kill what it started.
|
|
68
|
+
- **Artifact loads** — trained model / migration / config parses and does one forward pass or one query
|
|
69
|
+
- **The bug you were sent to fix** — a regression test reproducing it, written *before* the fix
|
|
70
|
+
|
|
71
|
+
Use fixtures small enough to commit. Never depend on the user's real data paths.
|
|
72
|
+
|
|
73
|
+
State plainly that these are smoke tests, not a suite.
|
|
74
|
+
|
|
75
|
+
## Phase 4 — Guardrails (only ones that pay for themselves)
|
|
76
|
+
|
|
77
|
+
Hooks, `.claude/settings.json`, and `/fewer-permission-prompts` are **Claude Code mechanisms**. On a harness without them (Codex CLI), skip the hook items and encode the same guardrails as instructions in the project's `AGENTS.md` instead: which files are untouchable, which derived file must be regenerated after editing which source.
|
|
78
|
+
|
|
79
|
+
Prefer few and deterministic. Candidates, in value order:
|
|
80
|
+
|
|
81
|
+
- **Auto-format/lint on write** — `PostToolUse` hook matching `Edit|Write`, running the repo's own formatter. Only if the repo already has one configured.
|
|
82
|
+
- **Regenerate derived files** — if editing source X requires regenerating Y (protobuf, OpenAPI clients, migrations, lockfiles), hook it, scoped inside the command to the relevant paths. This is the highest-value hook in most repos because humans forget it.
|
|
83
|
+
- **Protect the untouchables** — `PreToolUse` deny on production config, secrets, live model/deploy pointers.
|
|
84
|
+
- **Permission allowlist** — put the repo's read-only and verify commands into `.claude/settings.json` so the loop is not interrupted. `/fewer-permission-prompts` derives this from real transcripts.
|
|
85
|
+
|
|
86
|
+
Put project-scoped settings in the repo's `.claude/settings.json` (shared) or `.claude/settings.local.json` (personal, gitignored) — **not** in global settings.
|
|
87
|
+
|
|
88
|
+
Hooks execute automatically on the user's machine. Show the exact command before installing it, and never install one that pushes, deploys, deletes, or writes outside the repo.
|
|
89
|
+
|
|
90
|
+
## Phase 5 — Project notes file (`CLAUDE.md` / `AGENTS.md`)
|
|
91
|
+
|
|
92
|
+
Extend the notes file the repo already uses; if neither exists, create the one matching the current harness and add a one-line pointer from the other name so both find it. Write only what reading the code cannot tell you:
|
|
93
|
+
|
|
94
|
+
- How to run / test / verify — the commands from Phase 2
|
|
95
|
+
- Architecture facts that are load-bearing and non-obvious (what serves what, which file is source of truth)
|
|
96
|
+
- **Footguns and null results**: "X looks right but breaks Y", "tried A, measured no gain, do not retry", "always rebuild Z after W"
|
|
97
|
+
- Where the real docs live
|
|
98
|
+
|
|
99
|
+
Do not restate the directory tree, git history, or anything a `grep` answers. Keep it dense; every line costs context on every future session.
|
|
100
|
+
|
|
101
|
+
## Phase 6 — Prove it and report
|
|
102
|
+
|
|
103
|
+
1. **Flake check** — run the fast verify tier twice. A green that does not repeat is a flake, and a flaky verify makes every future red ambiguous; fixing or quarantining the flake comes before relying on the loop. (Skip the double run only when the repo has a single slow tier — say so.)
|
|
104
|
+
2. **Red check** — break a line a smoke test actually covers (flip an expected value or a return), confirm verify goes red, then restore. The break is one deliberate edit: **record file, line, and original text before making it, and restore by reverting exactly that edit.** Only use `git checkout -- <file>` if the file was committed before the break — on a file carrying uncommitted work it silently discards that work too, and it cannot restore the untracked test files this skill just wrote. Never use bare `git stash` here (it sweeps the whole tree and skips untracked files). Breaking an uncovered line and staying green proves nothing. A verify command that cannot fail is not a verify command.
|
|
105
|
+
|
|
106
|
+
Report:
|
|
107
|
+
- The one command to run (both tiers if split)
|
|
108
|
+
- What it does and does not cover
|
|
109
|
+
- What was added, and what was deliberately left out
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Read-only evidence scan for luciazero-bootstrap Phase 1.
|
|
3
|
+
# Prints what exists in a repo — docs, manifests, script/target names, CI run
|
|
4
|
+
# lines, test dirs, workspace markers. It surfaces candidates only; it never
|
|
5
|
+
# picks the verify command. Judgment stays with the agent.
|
|
6
|
+
#
|
|
7
|
+
# Usage: detect.sh [repo-root] (default: current directory)
|
|
8
|
+
# Exits 0 unless the target directory does not exist; absence of a section
|
|
9
|
+
# means nothing was found.
|
|
10
|
+
set -euo pipefail
|
|
11
|
+
|
|
12
|
+
cd "${1:-.}" 2>/dev/null || { printf 'detect.sh: no such directory: %s\n' "${1:-.}" >&2; exit 1; }
|
|
13
|
+
|
|
14
|
+
say() { printf '%s\n' "$*"; }
|
|
15
|
+
hr() { printf '\n== %s ==\n' "$*"; }
|
|
16
|
+
|
|
17
|
+
hr "repo: $(pwd)"
|
|
18
|
+
if git rev-parse --git-dir >/dev/null 2>&1; then
|
|
19
|
+
say "git repo: yes (toplevel: $(git rev-parse --show-toplevel))"
|
|
20
|
+
if [ -z "$(git ls-files . | head -1)" ]; then
|
|
21
|
+
say " WARNING: no tracked files under this dir — it may just sit inside an unrelated repo; revert/stash will not protect it"
|
|
22
|
+
fi
|
|
23
|
+
else
|
|
24
|
+
say "git repo: NO — no safe revert, stash, or bisect until 'git init' (ask first)"
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
hr "docs"
|
|
28
|
+
for F in README README.md README.rst CONTRIBUTING.md AGENTS.md CLAUDE.md docs; do
|
|
29
|
+
if [ -e "$F" ]; then say "exists: $F"; fi
|
|
30
|
+
done
|
|
31
|
+
|
|
32
|
+
hr "manifests"
|
|
33
|
+
for F in package.json pyproject.toml setup.py tox.ini noxfile.py Makefile \
|
|
34
|
+
justfile Justfile Cargo.toml go.mod build.gradle build.gradle.kts \
|
|
35
|
+
pom.xml composer.json Gemfile mix.exs CMakeLists.txt Package.swift; do
|
|
36
|
+
if [ -f "$F" ]; then say "exists: $F"; fi
|
|
37
|
+
done
|
|
38
|
+
|
|
39
|
+
if [ -f package.json ]; then
|
|
40
|
+
hr "package.json scripts"
|
|
41
|
+
if command -v python3 >/dev/null 2>&1; then
|
|
42
|
+
python3 -c 'import json,sys
|
|
43
|
+
d = json.load(open("package.json"))
|
|
44
|
+
for k, v in d.get("scripts", {}).items():
|
|
45
|
+
print(f" {k}: {v}")' 2>/dev/null || say " (unparseable package.json)"
|
|
46
|
+
else
|
|
47
|
+
sed -n '/"scripts"[[:space:]]*:/,/}/p' package.json
|
|
48
|
+
fi
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
if [ -f Makefile ]; then
|
|
52
|
+
hr "Makefile targets"
|
|
53
|
+
grep -E '^[A-Za-z0-9_.-]+:' Makefile | cut -d: -f1 | sed 's/^/ /' | head -30 || true
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
for J in justfile Justfile; do
|
|
57
|
+
if [ -f "$J" ]; then
|
|
58
|
+
hr "$J recipes"
|
|
59
|
+
grep -E '^[A-Za-z0-9_-]+.*:' "$J" | sed 's/^/ /' | head -30 || true
|
|
60
|
+
fi
|
|
61
|
+
done
|
|
62
|
+
|
|
63
|
+
hr "ci — whatever CI runs is the honest verify command; read these files yourself"
|
|
64
|
+
for C in .github/workflows/*.yml .github/workflows/*.yaml .gitlab-ci.yml .circleci/config.yml; do
|
|
65
|
+
if [ -f "$C" ]; then
|
|
66
|
+
say "file: $C"
|
|
67
|
+
grep -nE '^[[:space:]]*(-[[:space:]]+)?(run|script)[[:space:]]*:' "$C" | sed 's/^/ /' | head -30 || true
|
|
68
|
+
fi
|
|
69
|
+
done
|
|
70
|
+
|
|
71
|
+
hr "test dirs / files (top two levels)"
|
|
72
|
+
find . -maxdepth 2 \( -name .git -o -name node_modules -o -name .venv -o -name vendor \) -prune -o \
|
|
73
|
+
\( -type d \( -name tests -o -name test -o -name spec -o -name __tests__ \) -print \) 2>/dev/null | sed 's/^/ /' | head -10 || true
|
|
74
|
+
find . -maxdepth 2 \( -name .git -o -name node_modules -o -name .venv -o -name vendor \) -prune -o \
|
|
75
|
+
\( -type f \( -name '*_test.*' -o -name 'test_*.*' -o -name '*.test.*' -o -name '*.spec.*' \) -print \) 2>/dev/null | sed 's/^/ /' | head -10 || true
|
|
76
|
+
|
|
77
|
+
hr "workspace / monorepo markers"
|
|
78
|
+
for F in pnpm-workspace.yaml turbo.json nx.json lerna.json go.work; do
|
|
79
|
+
if [ -f "$F" ]; then say "exists: $F"; fi
|
|
80
|
+
done
|
|
81
|
+
if [ -f package.json ] && grep -q '"workspaces"' package.json; then say "package.json declares workspaces"; fi
|
|
82
|
+
if [ -f Cargo.toml ] && grep -q '^\[workspace\]' Cargo.toml; then say "Cargo.toml declares [workspace]"; fi
|
|
83
|
+
|
|
84
|
+
exit 0
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: retro
|
|
3
|
+
description: Harvest lessons from the session into the project's permanent notes. Use after finishing a hard task, a long debugging session, or any work that hit dead ends — when the user says "run a retro", "record what we learned", "จดบทเรียน", or when a task ends having disproven an approach that looked right.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Retro — turn experience into recorded knowledge
|
|
7
|
+
|
|
8
|
+
The doctrine says: *never re-derive a dead end twice.* This skill is the procedure that makes it actually happen. A team that logs its null results stops paying for the same experiment twice — that is the cheapest intelligence upgrade available.
|
|
9
|
+
|
|
10
|
+
## 1. Scan the session
|
|
11
|
+
|
|
12
|
+
Walk back through the work just finished and list candidates:
|
|
13
|
+
|
|
14
|
+
- What took the longest, and was the time spent where you first expected?
|
|
15
|
+
- Which attempts **failed**, and what was the real cause once found?
|
|
16
|
+
- What looked like the right approach but was wrong — and why exactly?
|
|
17
|
+
- What surprised you: environment quirks, undocumented behavior, a flag or version that mattered?
|
|
18
|
+
- What did you have to re-discover that should already have been written down?
|
|
19
|
+
|
|
20
|
+
**Also read the discipline stats**, if the enforcement pack is installed: `luciazero-stats.log` in the harness config dir (`~/.claude`), one line per stop outcome. Recurring `nudge` or `strict-block` lines for this project are behavioral lessons — e.g. repeated nudges usually mean the repo has no `LUCIAZERO_VERIFY_CMD` set or the fast verify tier is too slow to run habitually. Treat those patterns as candidates like any other.
|
|
21
|
+
|
|
22
|
+
## 2. Filter hard
|
|
23
|
+
|
|
24
|
+
Record only what **reading the code cannot tell a future agent**:
|
|
25
|
+
|
|
26
|
+
- ✅ Null results: "tried X, measured no gain / broke Y — do not retry without new evidence"
|
|
27
|
+
- ✅ Footguns: "A looks correct but silently breaks B"
|
|
28
|
+
- ✅ Environment facts: version pins, platform quirks, commands that must follow other commands
|
|
29
|
+
- ✅ Why a tempting approach is wrong (with the one-line evidence)
|
|
30
|
+
- ❌ What the diff/git history already says
|
|
31
|
+
- ❌ Anything a `grep` or `--help` answers
|
|
32
|
+
- ❌ Session-only details (temp paths, one-off values)
|
|
33
|
+
|
|
34
|
+
A null result is worth exactly as much as a success. If the session proved nothing new, say so and stop — an empty retro is a valid result; padding it with restated code facts makes every future session pay for noise.
|
|
35
|
+
|
|
36
|
+
## 3. Route it, then write it
|
|
37
|
+
|
|
38
|
+
**First decide who the lesson is true for:**
|
|
39
|
+
|
|
40
|
+
- **Anyone who clones the repo** — code behavior, build quirks, disproven approaches → the committed notes below. A **debugged failure** specifically goes to the repo's lesson ledger `docs/lessons.md` in this fixed shape, so `/debug` can seed its hypothesis ledger from it next time:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
## <one-line symptom, greppable — include the error string>
|
|
44
|
+
cause: <root cause> | proven-by: `<command>` | fix: <what fixed it> | date: YYYY-MM-DD
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- **True in every repository** — engineering lessons not tied to this codebase ("intermittent async test: check timezone pinning before touching the test") → append one line to `luciazero-heuristics.md` in the harness config dir (`~/.claude` / `~/.codex`). Hard rules: one line per lesson, same update-in-place/dedup discipline, **cap the file at 100 lines** — when full, drop the weakest entry rather than growing (an unbounded heuristics file becomes context tax, the exact failure this pack exists to prevent). Never personal paths or secrets, even here.
|
|
48
|
+
- **Only this machine or this user** — local paths, installed tool versions, personal preferences, credential locations → must **never** be committed. If the harness provides a persistent memory directory (Claude Code announces its per-project `memory/` dir and `MEMORY.md` index in context when enabled), write it there and update the index, applying the same format, dedup, and prune rules. If no memory system exists (Codex CLI, or memory disabled), keep only the generalization that is true for anyone who clones the repo — never personal preferences or credential locations, even generalized; if nothing repo-true remains, state the lesson in the retro report instead of writing it anywhere — an honest gap beats a note no harness will ever load.
|
|
49
|
+
|
|
50
|
+
Format, one entry per lesson:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
- **<topic>** — tried <X>; failed because <Y>; do <Z> instead. (evidence: <shortest decisive line>, <date>)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Committed destinations:
|
|
57
|
+
|
|
58
|
+
- **Project notes file** (`CLAUDE.md` / `AGENTS.md` — extend the one the repo uses) — if the lesson is load-bearing for most future sessions and fits in 1–2 lines.
|
|
59
|
+
- **`docs/<topic>.md`** — if it needs detail (measurements, alternatives tried, tables); then put a one-line pointer in the notes file.
|
|
60
|
+
- Follow the project's existing convention if it already has an experiments log or notes dir — extend it, do not invent a parallel one.
|
|
61
|
+
|
|
62
|
+
## 4. Dedup and prune
|
|
63
|
+
|
|
64
|
+
Before writing, read the existing notes (and `MEMORY.md` when routing to harness memory):
|
|
65
|
+
|
|
66
|
+
- If a note on the topic exists, **update it in place** — do not append a duplicate.
|
|
67
|
+
- If the session **disproved** an existing note, correct or delete it and say so in the report.
|
|
68
|
+
- The same two rules govern `docs/lessons.md` and `luciazero-heuristics.md`: a ledger entry whose cause this session disproved gets corrected or deleted — a stale lesson mis-seeds every future `/debug`.
|
|
69
|
+
|
|
70
|
+
## 5. Verify as a future reader
|
|
71
|
+
|
|
72
|
+
Re-read each entry pretending it is six months later and context is gone. Would you know what to do differently? If an entry needs this session's context to make sense, rewrite it with the missing facts inline.
|
|
73
|
+
|
|
74
|
+
Report what was recorded, where, and what was deliberately not recorded (and why).
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Remove the Luciazero doctrine + skills from OpenAI Codex CLI (~/.codex).
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
for ARG in "$@"; do
|
|
6
|
+
echo "unknown option: ${ARG} (uninstall-codex.sh takes no options)" >&2; exit 1
|
|
7
|
+
done
|
|
8
|
+
|
|
9
|
+
CODEX_DIR="${CODEX_HOME:-$HOME/.codex}"
|
|
10
|
+
AGENTS_MD="${CODEX_DIR}/AGENTS.md"
|
|
11
|
+
START='<!-- luciazero:start -->'
|
|
12
|
+
END='<!-- luciazero:end -->'
|
|
13
|
+
|
|
14
|
+
# collision-proof backup path for $1 (two runs in the same second must not overwrite)
|
|
15
|
+
bakpath() {
|
|
16
|
+
B="$1.bak.$(date +%Y%m%d%H%M%S)"
|
|
17
|
+
N=1
|
|
18
|
+
while [ -e "${B}" ]; do B="$1.bak.$(date +%Y%m%d%H%M%S).${N}"; N=$((N+1)); done
|
|
19
|
+
printf '%s' "${B}"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
echo "Removing from ${CODEX_DIR}"
|
|
23
|
+
|
|
24
|
+
rm -f "${CODEX_DIR}/.luciazero-version"
|
|
25
|
+
for SKILL in luciazero-bootstrap retro debug 'done' handoff experiment reviewer; do
|
|
26
|
+
rm -rf "${CODEX_DIR}/skills/${SKILL}"
|
|
27
|
+
echo " ok skills/${SKILL}"
|
|
28
|
+
done
|
|
29
|
+
|
|
30
|
+
if [ -f "${AGENTS_MD}" ] && grep -qF "${START}" "${AGENTS_MD}"; then
|
|
31
|
+
BACKUP="$(bakpath "${AGENTS_MD}")"
|
|
32
|
+
cp "${AGENTS_MD}" "${BACKUP}"
|
|
33
|
+
awk -v s="${START}" -v e="${END}" '
|
|
34
|
+
$0==s {inblock=1; next}
|
|
35
|
+
$0==e {inblock=0; next}
|
|
36
|
+
!inblock {print}
|
|
37
|
+
' "${AGENTS_MD}" > "${AGENTS_MD}.tmp"
|
|
38
|
+
mv "${AGENTS_MD}.tmp" "${AGENTS_MD}"
|
|
39
|
+
[ -s "${AGENTS_MD}" ] || rm -f "${AGENTS_MD}"
|
|
40
|
+
echo " ok removed doctrine block (backup: $(basename "${BACKUP}"))"
|
|
41
|
+
else
|
|
42
|
+
echo " ok no doctrine block in AGENTS.md"
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
if [ -f "${CODEX_DIR}/luciazero-heuristics.md" ]; then
|
|
46
|
+
echo " kept luciazero-heuristics.md (learned data) — delete manually if unwanted"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
echo
|
|
50
|
+
echo "Done. Other AGENTS.md content was left untouched."
|
package/uninstall.sh
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Remove the Luciazero doctrine + bootstrap skill from ~/.claude/
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
for ARG in "$@"; do
|
|
6
|
+
echo "unknown option: ${ARG} (uninstall.sh takes no options)" >&2; exit 1
|
|
7
|
+
done
|
|
8
|
+
|
|
9
|
+
CLAUDE_DIR="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
|
|
10
|
+
DOCTRINE="luciazero.md"
|
|
11
|
+
IMPORT_LINE="@${DOCTRINE}"
|
|
12
|
+
GLOBAL_MD="${CLAUDE_DIR}/CLAUDE.md"
|
|
13
|
+
|
|
14
|
+
# collision-proof backup path for $1 (two runs in the same second must not overwrite)
|
|
15
|
+
bakpath() {
|
|
16
|
+
B="$1.bak.$(date +%Y%m%d%H%M%S)"
|
|
17
|
+
N=1
|
|
18
|
+
while [ -e "${B}" ]; do B="$1.bak.$(date +%Y%m%d%H%M%S).${N}"; N=$((N+1)); done
|
|
19
|
+
printf '%s' "${B}"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
echo "Removing from ${CLAUDE_DIR}"
|
|
23
|
+
|
|
24
|
+
rm -f "${CLAUDE_DIR}/${DOCTRINE}"
|
|
25
|
+
rm -f "${CLAUDE_DIR}/.luciazero-version"
|
|
26
|
+
echo " ok ${DOCTRINE}"
|
|
27
|
+
|
|
28
|
+
for SKILL in luciazero-bootstrap retro debug 'done' handoff experiment; do
|
|
29
|
+
rm -rf "${CLAUDE_DIR}/skills/${SKILL}"
|
|
30
|
+
echo " ok skills/${SKILL}"
|
|
31
|
+
done
|
|
32
|
+
|
|
33
|
+
rm -f "${CLAUDE_DIR}/agents/reviewer.md"
|
|
34
|
+
echo " ok agents/reviewer.md"
|
|
35
|
+
|
|
36
|
+
# enforcement pack, if it was installed with --with-hooks.
|
|
37
|
+
# Order matters: clean settings.json FIRST and delete the hook files only if
|
|
38
|
+
# that succeeded — otherwise Claude Code would keep executing references to
|
|
39
|
+
# files we just deleted.
|
|
40
|
+
SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
41
|
+
SETTINGS="${CLAUDE_DIR}/settings.json"
|
|
42
|
+
HOOKS_CLEAN=1
|
|
43
|
+
if [ -f "${SETTINGS}" ] && grep -qF "${CLAUDE_DIR}/hooks/luciazero-" "${SETTINGS}"; then
|
|
44
|
+
if command -v python3 >/dev/null 2>&1; then
|
|
45
|
+
cp "${SETTINGS}" "$(bakpath "${SETTINGS}")"
|
|
46
|
+
# exact-path matching only: never touch a user's own hook that merely
|
|
47
|
+
# shares a basename with ours
|
|
48
|
+
if python3 - "${SETTINGS}" "${CLAUDE_DIR}" 2>/dev/null <<'PY'
|
|
49
|
+
import json, os, sys
|
|
50
|
+
|
|
51
|
+
path, claude_dir = sys.argv[1], sys.argv[2]
|
|
52
|
+
with open(path) as f:
|
|
53
|
+
settings = json.load(f)
|
|
54
|
+
|
|
55
|
+
MARKERS = (
|
|
56
|
+
os.path.join(claude_dir, "hooks", "luciazero-verify.sh"),
|
|
57
|
+
os.path.join(claude_dir, "hooks", "luciazero-statusline.sh"),
|
|
58
|
+
)
|
|
59
|
+
def ours(cmd):
|
|
60
|
+
return any(cmd == m or cmd.startswith(m + " ") for m in MARKERS)
|
|
61
|
+
|
|
62
|
+
changed = False
|
|
63
|
+
hooks = settings.get("hooks") or {}
|
|
64
|
+
for event in list(hooks):
|
|
65
|
+
kept = []
|
|
66
|
+
for entry in hooks[event]:
|
|
67
|
+
inner = [h for h in entry.get("hooks", []) if not ours(h.get("command", ""))]
|
|
68
|
+
if inner != entry.get("hooks", []):
|
|
69
|
+
changed = True
|
|
70
|
+
if inner:
|
|
71
|
+
entry = dict(entry)
|
|
72
|
+
entry["hooks"] = inner
|
|
73
|
+
kept.append(entry)
|
|
74
|
+
# entry emptied by removal -> dropped
|
|
75
|
+
else:
|
|
76
|
+
kept.append(entry)
|
|
77
|
+
if kept:
|
|
78
|
+
hooks[event] = kept
|
|
79
|
+
elif hooks[event] != kept:
|
|
80
|
+
del hooks[event]
|
|
81
|
+
changed = True
|
|
82
|
+
|
|
83
|
+
sl = settings.get("statusLine") or {}
|
|
84
|
+
if isinstance(sl, dict) and ours(sl.get("command", "")):
|
|
85
|
+
del settings["statusLine"]
|
|
86
|
+
changed = True
|
|
87
|
+
|
|
88
|
+
if changed:
|
|
89
|
+
with open(path, "w") as f:
|
|
90
|
+
json.dump(settings, f, indent=2, ensure_ascii=False)
|
|
91
|
+
f.write("\n")
|
|
92
|
+
PY
|
|
93
|
+
then
|
|
94
|
+
echo " ok removed hook entries from settings.json"
|
|
95
|
+
else
|
|
96
|
+
HOOKS_CLEAN=0
|
|
97
|
+
echo " !! could not clean settings.json (invalid JSON?) — hook files kept so nothing dangles; remove the luciazero-* entries manually, then delete ${CLAUDE_DIR}/hooks/luciazero-*.sh" >&2
|
|
98
|
+
fi
|
|
99
|
+
else
|
|
100
|
+
HOOKS_CLEAN=0
|
|
101
|
+
echo " !! python3 not found — settings.json untouched; hook files kept so nothing dangles" >&2
|
|
102
|
+
fi
|
|
103
|
+
else
|
|
104
|
+
echo " ok no enforcement-pack entries in settings.json"
|
|
105
|
+
fi
|
|
106
|
+
if [ "${HOOKS_CLEAN}" = 1 ]; then
|
|
107
|
+
for H in luciazero-verify.sh luciazero-statusline.sh; do
|
|
108
|
+
F="${CLAUDE_DIR}/hooks/${H}"
|
|
109
|
+
if [ -f "${F}" ]; then
|
|
110
|
+
if cmp -s "${F}" "${SRC}/claude/hooks/${H}" 2>/dev/null; then
|
|
111
|
+
rm -f "${F}"
|
|
112
|
+
echo " ok hooks/${H}"
|
|
113
|
+
else
|
|
114
|
+
echo " !! hooks/${H} differs from the shipped version (customized or newer?) — left in place" >&2
|
|
115
|
+
fi
|
|
116
|
+
fi
|
|
117
|
+
done
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
if [ -f "${GLOBAL_MD}" ] && grep -qF "${IMPORT_LINE}" "${GLOBAL_MD}"; then
|
|
121
|
+
BACKUP="$(bakpath "${GLOBAL_MD}")"
|
|
122
|
+
cp "${GLOBAL_MD}" "${BACKUP}"
|
|
123
|
+
# grep exits 1 when the import line was the only content — that is fine
|
|
124
|
+
grep -vxF "${IMPORT_LINE}" "${GLOBAL_MD}" > "${GLOBAL_MD}.tmp" || [ $? -eq 1 ]
|
|
125
|
+
mv "${GLOBAL_MD}.tmp" "${GLOBAL_MD}"
|
|
126
|
+
[ -s "${GLOBAL_MD}" ] || rm -f "${GLOBAL_MD}"
|
|
127
|
+
echo " ok removed import line (backup: $(basename "${BACKUP}"))"
|
|
128
|
+
else
|
|
129
|
+
echo " ok no import line in CLAUDE.md"
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
for KEEP in luciazero-stats.log luciazero-heuristics.md; do
|
|
133
|
+
if [ -f "${CLAUDE_DIR}/${KEEP}" ]; then
|
|
134
|
+
echo " kept ${KEEP} (learned data) — delete manually if unwanted"
|
|
135
|
+
fi
|
|
136
|
+
done
|
|
137
|
+
|
|
138
|
+
echo
|
|
139
|
+
echo "Done. Other CLAUDE.md content was left untouched."
|