@oneie/claude 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/agents/w1-recon.md +9 -4
  2. package/agents/w2-decide.md +51 -28
  3. package/agents/w3-edit.md +70 -78
  4. package/agents/w4-verify.md +164 -69
  5. package/commands/browser.md +98 -35
  6. package/commands/cc-connect.md +6 -0
  7. package/commands/chat.md +13 -1
  8. package/commands/close.md +45 -19
  9. package/commands/create.md +20 -10
  10. package/commands/db-sync.md +5 -1
  11. package/commands/deploy.md +174 -87
  12. package/commands/do-autonomous.md +31 -20
  13. package/commands/do-improve.md +4 -4
  14. package/commands/do-show.md +4 -3
  15. package/commands/do.md +53 -13
  16. package/commands/go.md +75 -0
  17. package/commands/improve.md +4 -2
  18. package/commands/kill.md +6 -8
  19. package/commands/notify.md +15 -2
  20. package/commands/oo-push.md +24 -9
  21. package/commands/rag.md +6 -0
  22. package/commands/release.md +46 -25
  23. package/commands/restart.md +5 -4
  24. package/commands/see.md +45 -35
  25. package/commands/skill-create.md +38 -5
  26. package/commands/sync.md +21 -11
  27. package/hooks/scripts/auto-continue.sh +70 -0
  28. package/hooks/scripts/branch-pin.sh +85 -0
  29. package/hooks/scripts/git-add-guard.sh +16 -5
  30. package/hooks/scripts/post-edit-check.sh +16 -0
  31. package/hooks/scripts/session-start.sh +13 -8
  32. package/hooks/scripts/sync-priority-todo.sh +5 -0
  33. package/package.json +1 -1
  34. package/rules/api.md +9 -0
  35. package/rules/design.md +13 -3
  36. package/rules/documentation.md +30 -71
  37. package/rules/engine.md +8 -1
  38. package/rules/ui.md +5 -1
  39. package/scripts/__pycache__/do-rank.cpython-313.pyc +0 -0
  40. package/scripts/browser-check.mjs +44 -103
  41. package/scripts/cc-events-proof.sh +13 -12
  42. package/scripts/chrome.mjs +381 -0
  43. package/scripts/do-analyze.sh +109 -4
  44. package/scripts/do-auto.sh +350 -43
  45. package/scripts/do-consumer-sweep.sh +72 -0
  46. package/scripts/do-derives-check.sh +88 -0
  47. package/scripts/do-fleet.sh +50 -1
  48. package/scripts/do-killswitch-audit.py +33 -14
  49. package/scripts/do-promise-lint.sh +150 -4
  50. package/scripts/do-promise-settle.sh +131 -9
  51. package/scripts/do-prove.sh +197 -17
  52. package/scripts/do-rank.py +606 -20
  53. package/scripts/do-rubric.py +21 -2
  54. package/scripts/do-signal.sh +157 -17
  55. package/scripts/do-smoke.sh +9 -0
  56. package/scripts/do-substrate-check.sh +49 -0
  57. package/scripts/do-tasks-wire-check.sh +81 -0
  58. package/scripts/do-tier.sh +90 -5
  59. package/scripts/do-ui-gate.sh +332 -0
  60. package/scripts/do-untracked-gate.sh +231 -0
  61. package/scripts/do-walk.sh +344 -0
  62. package/scripts/factory-check.sh +747 -0
  63. package/scripts/factory-repo.sh +1361 -0
  64. package/scripts/factory-tasks-check.sh +85 -0
  65. package/scripts/outcome-pull.ts +279 -0
  66. package/scripts/promise-manifest.mjs +167 -0
  67. package/scripts/reconcile-allow.txt +5 -0
  68. package/scripts/rubric-weights.json +64 -0
  69. package/scripts/spine-canary.sh +20 -0
  70. package/scripts/typedb-cluster-status.sh +128 -0
  71. package/scripts/typedb-env.sh +182 -0
  72. package/scripts/typedb-flap-recorder.sh +85 -0
  73. package/scripts/typedb-probes/containment-probe.py +88 -0
  74. package/scripts/typedb-probes/panic-probe-version.py +92 -0
  75. package/scripts/typedb-probes/panic-probe.py +77 -0
  76. package/scripts/typedb-scratch.sh +73 -0
  77. package/scripts/urls-lint.sh +58 -0
  78. package/scripts/w4-rubric.ts +96 -12
  79. package/scripts/wf-check.mjs +75 -0
  80. package/skills/ai-ui/SKILL.md +1 -1
  81. package/skills/astro/SKILL.md +177 -132
  82. package/skills/astro/add-content-collection.md +29 -13
  83. package/skills/astro/check-build.md +19 -13
  84. package/skills/astro/create-component.md +36 -9
  85. package/skills/astro/create-page.md +39 -10
  86. package/skills/astro/optimize-performance.md +36 -8
  87. package/skills/cli/SKILL.md +254 -220
  88. package/skills/dev/SKILL.md +1 -1
  89. package/skills/directory-autofill/SKILL.md +68 -0
  90. package/skills/docs/SKILL.md +4 -4
  91. package/skills/mcp/SKILL.md +186 -156
  92. package/skills/promise-make/SKILL.md +2 -2
  93. package/skills/puck/SKILL.md +465 -250
  94. package/skills/react19/SKILL.md +196 -296
  95. package/skills/reactflow/SKILL.md +387 -412
  96. package/skills/sdk/SKILL.md +167 -106
  97. package/skills/shadcn/SKILL.md +245 -201
  98. package/skills/signal/SKILL.md +5 -0
  99. package/skills/sui/SKILL.md +6 -1
  100. package/skills/tutorial/SKILL.md +15 -0
  101. package/skills/typedb/SKILL.md +427 -217
  102. package/skills/typedb/examples/python-patterns.py +11 -4
  103. package/skills/typedb/examples/query-patterns.tql +8 -3
  104. package/skills/typedb/examples/schema-patterns.tql +4 -2
  105. package/skills/typedb/reference/migration-2x-3x.md +19 -1
  106. package/skills/typedb/reference/python-driver.md +17 -1
  107. package/skills/voice/SKILL.md +117 -0
  108. package/skills/writer/SKILL.md +29 -12
  109. package/templates/template-feature.md +26 -1
  110. package/templates/template-tests.md +4 -0
  111. package/templates/template-todo.md +65 -10
package/commands/see.md CHANGED
@@ -17,7 +17,7 @@ Read the world — query substrate state without emitting signals.
17
17
  | `evolved` | Agents that rewrote their system prompts | L5 |
18
18
  | `revenue` | Per-path earnings from L4 economic loop | L4 |
19
19
  | `events [--since T]` | Signal history and Four Outcomes audit | L1 |
20
- | `memory <uid>` | Full memory card for an actor (reveal) | L6 |
20
+ | `memory <uid>` | Unseal one PII field for an actor (reveal) — authenticated | L6 |
21
21
 
22
22
  ## Routing
23
23
 
@@ -26,22 +26,30 @@ No mark(), no warn(), no side effects. Every noun is read-only.
26
26
 
27
27
  | Noun | Primitive | Source |
28
28
  |------|-----------|--------|
29
- | tasks | `follow()` queue read | `/api/tasks` or `scanTodos()` |
30
- | highways | `follow()` path read | `/api/state` strength ≥ 50 |
31
- | toxic | `follow()` path read | `/api/state` resistance > strength |
32
- | frontiers | `follow()` gap read | `/api/state` <10% traversed |
33
- | paths | `follow()` path query | `/api/state` filtered |
34
- | hypotheses | TypeDB read | learning entities |
35
- | evolved | TypeDB read | units where generation > 1 |
36
- | revenue | TypeDB read | paths with revenue attribute |
37
- | events | TypeDB read | signal history |
38
- | memory | `reveal(uid)` | `/api/memory/reveal/:uid` |
29
+ | tasks | `follow()` queue read | `.claude/scripts/do-rank.py` |
30
+ | highways | `follow()` path read | `GET /api/export/highways` |
31
+ | toxic | `follow()` path read | `GET /api/export/toxic` |
32
+ | frontiers | `follow()` gap read | `GET /api/frontiers` |
33
+ | paths | `follow()` path query | `GET /api/paths` |
34
+ | hypotheses | TypeDB read | `GET /api/export/hypotheses` |
35
+ | evolved | TypeDB read | `GET /api/export/units`, filter `generation > 1` |
36
+ | revenue | TypeDB read | `GET /api/revenue` |
37
+ | events | TypeDB read | signal history — no GET route (see below) |
38
+ | memory | `reveal(uid)` | `GET /api/pii/reveal/:uid?field=` |
39
+
40
+ **Not built (do not invoke, do not describe as live) — verified 2026-08-02:**
41
+ `GET /api/tasks`, `GET /api/state`, `GET /api/memory/reveal/:uid`, and
42
+ `scanTodos()` in `src/engine/task-parse.ts` (the whole `src/engine/` dir holds
43
+ only `rubric.ts`). Every noun that used to name one has been repointed above.
44
+ `/api/events` exists but is **POST-only tracking ingest**, not a signal-history
45
+ read — do not GET it.
39
46
 
40
47
  ## Steps
41
48
 
42
49
  ### tasks
43
50
 
44
- 1. GET `http://localhost:4321/api/tasks` (falls back to `scanTodos()` in `src/engine/task-parse.ts` if server not running)
51
+ 1. `python3 .claude/scripts/do-rank.py` the ranker reads `text/*-todo.md` directly and needs no dev server. Add `--tasks` for the tagged-signal view, `--json` for machine output, `--top N` to cap.
52
+ - **The one exception to this file's no-side-effects rule.** The ranker refreshes a `text/task-paths.json` memo as it runs. It does **not** write `todo.md` — that is `hook:sync-priority-todo`, fired on Stop and SessionStart. No substrate write, no `mark()`/`warn()`.
45
53
  2. Filter by `$ARGUMENTS` if provided — tags or phase (e.g. `/see tasks build P0`, `/see tasks C1`)
46
54
  3. Report tasks sorted by effective priority (priority score + pheromone strength − resistance):
47
55
  - Name, id, priority formula (e.g. `90 = critical=30 + C1=40 + dev=20`)
@@ -56,7 +64,7 @@ No mark(), no warn(), no side effects. Every noun is read-only.
56
64
 
57
65
  ### highways
58
66
 
59
- 1. GET `http://localhost:4321/api/export/highways?context=1` (falls back to `/api/state` if server not running)
67
+ 1. GET `http://localhost:4321/api/export/highways?limit=50` — the route takes `limit` (default 50, capped 200) and an optional `from=<aid>` to scope to one source actor. There is no `context=` param and no `/api/state` fallback.
60
68
  2. Show paths where `strength ≥ 50`, sorted by strength desc (default limit 20; use `--limit N` to override)
61
69
  3. Each: from → to, strength, traversals, revenue — and `context: <docs>` if contextHint is present
62
70
  4. Report:
@@ -69,7 +77,8 @@ No mark(), no warn(), no side effects. Every noun is read-only.
69
77
 
70
78
  ### toxic
71
79
 
72
- 1. GET `http://localhost:4321/api/state`
80
+ 1. GET `http://localhost:4321/api/export/toxic?limit=200` (limit capped at 500; returns warned/faded paths with `resistance > 0`, sorted by resistance desc)
81
+ - **Empty ≠ clean.** Every `/api/export/*` route scopes via `scopeToGroup(viewer, …)`, defaulting to `viewer='end_user'` / `workspace='default'`. An unauthenticated call returns an empty set, not a 401 — so "0 toxic paths" may mean "not authorized to see any". The same applies to `hypotheses` and `evolved` below. Authenticate, or read the count as unknown.
73
82
  2. Show paths where `resistance > strength`
74
83
  3. Each: from → to, resistance, strength, hypothesis (if any)
75
84
  4. Report:
@@ -80,7 +89,7 @@ No mark(), no warn(), no side effects. Every noun is read-only.
80
89
 
81
90
  ### frontiers
82
91
 
83
- 1. GET `http://localhost:4321/api/state`
92
+ 1. GET `http://localhost:4321/api/frontiers` (optional `?limit=N`)
84
93
  2. Show tag clusters with <10% traversal rate
85
94
  3. Each: tag cluster, % explored, expected value
86
95
  4. Report:
@@ -91,14 +100,14 @@ No mark(), no warn(), no side effects. Every noun is read-only.
91
100
 
92
101
  ### paths
93
102
 
94
- 1. GET `http://localhost:4321/api/state`
95
- 2. Filter by `--from` and/or `--to` if provided in `$ARGUMENTS`
103
+ 1. GET `http://localhost:4321/api/paths` — params are `from=<aid>`, `to=<aid>`, `limit` (default 20), `min_strength` (default 1)
104
+ 2. Filter by `--from` and/or `--to` if provided in `$ARGUMENTS` — pass them through as `from=`/`to=`
96
105
  3. Show matching paths: from → to, strength, resistance, net weight (strength − resistance)
97
106
  4. Report all matching paths with full pheromone state
98
107
 
99
108
  ### hypotheses
100
109
 
101
- 1. Query TypeDB: match hypothesis entities
110
+ 1. GET `http://localhost:4321/api/export/hypotheses?limit=100` (or query TypeDB directly for hypothesis entities)
102
111
  2. Show each: pattern, confidence, created, reinforced count
103
112
  3. Report:
104
113
  ```
@@ -108,7 +117,7 @@ No mark(), no warn(), no side effects. Every noun is read-only.
108
117
 
109
118
  ### evolved
110
119
 
111
- 1. Query TypeDB: units where `generation > 1`
120
+ 1. GET `http://localhost:4321/api/export/units`, then filter to `generation > 1` client-side (the route has no generation filter) — or query TypeDB directly
112
121
  2. Show each: uid, name, generation, current model, last evolution timestamp
113
122
  3. Report:
114
123
  ```
@@ -118,7 +127,7 @@ No mark(), no warn(), no side effects. Every noun is read-only.
118
127
 
119
128
  ### revenue
120
129
 
121
- 1. Query TypeDB: paths with revenue attribute, sorted desc
130
+ 1. GET `http://localhost:4321/api/revenue` (or query TypeDB for paths with a revenue attribute, sorted desc)
122
131
  2. Show per-path earnings
123
132
  3. Report:
124
133
  ```
@@ -128,7 +137,7 @@ No mark(), no warn(), no side effects. Every noun is read-only.
128
137
 
129
138
  ### events
130
139
 
131
- 1. Query TypeDB signals, optionally filtered by `--since T` from `$ARGUMENTS`
140
+ 1. Query TypeDB signals directly, optionally filtered by `--since T` from `$ARGUMENTS`. **No HTTP read route exists** — `/api/events` is POST-only tracking ingest and will not serve this.
132
141
  2. Show each signal: receiver, data summary, outcome, timestamp
133
142
  3. Report:
134
143
  ```
@@ -139,23 +148,24 @@ No mark(), no warn(), no side effects. Every noun is read-only.
139
148
  ### memory
140
149
 
141
150
  1. Extract `<uid>` from `$ARGUMENTS` (e.g. `/see memory person:a7f3`)
142
- 2. GET `http://localhost:4321/api/memory/reveal/<uid>`
143
- 3. Display the full MemoryCard:
144
- - **Actor**: uid, kind, firstSeen
145
- - **Hypotheses**: pattern + confidence (asserted capped at 0.30)
146
- - **Highways**: top paths by strength
147
- - **Signals**: last 200 episodes
148
- - **Groups**: memberships
149
- - **Capabilities**: offered skills + prices
150
- - **Frontier**: unexplored tag clusters
151
- 4. Report:
151
+ 2. GET `http://localhost:4321/api/pii/reveal/<uid>?field=email` — this is the only
152
+ shipped `reveal`. It unseals **one PII field at a time**
153
+ (`email|phone|address|name|dob|custom`), not a memory card.
154
+ - **Authenticated and audited.** It calls `requireAuth` + `requireContactOwner`,
155
+ so an anonymous or non-owning caller gets denied. Rate-limited to 100
156
+ reads/hour per reader; every read emits a `pii.read` audit event.
157
+ - The MCP tool `reveal` is the same route.
158
+ 3. Report:
152
159
  ```
153
- Memory: <uid>
154
- Hypotheses: N (observed=X asserted=Y)
155
- Highways: N paths
156
- Frontier: [tag1, tag2, ...] — N unexplored tags
160
+ Reveal: <uid> field=<field>
157
161
  ```
158
162
 
163
+ **The aggregate MemoryCard was never built.** There is no route returning
164
+ hypotheses + highways + last-200 signals + groups + capabilities + frontier for
165
+ one actor. To assemble that view today, compose the other nouns for that uid:
166
+ `/see hypotheses`, `/see highways` (`?from=<uid>`), `/see paths` (`?from=<uid>`),
167
+ `/see frontiers`. Do not describe a single-call memory card as live.
168
+
159
169
  ---
160
170
 
161
171
  *Every `/see` query is a `follow()` call — the substrate answers without learning.*
@@ -27,7 +27,7 @@ tail -5 text/learnings.md
27
27
 
28
28
  # Recent cycle diff (what actually changed)
29
29
  git diff HEAD~1 HEAD --stat
30
- git diff HEAD~1 HEAD -- $(git diff HEAD~1 HEAD --name-only | grep -v 'text/\|text/' | head -20)
30
+ git diff HEAD~1 HEAD -- $(git diff HEAD~1 HEAD --name-only | grep -v 'text/' | head -20)
31
31
  ```
32
32
 
33
33
  **Step 2 — Extract the pattern (Haiku · low)**
@@ -42,9 +42,25 @@ Ignore one-off specifics (feature names, slugs). Keep the reusable skeleton.
42
42
 
43
43
  **Step 3 — Write `.claude/skills/<slug>/SKILL.md`**
44
44
 
45
+ The path is `.claude/skills/<slug>/SKILL.md` — a **directory** containing
46
+ `SKILL.md`. A bare `.claude/skills/<slug>.md` is not loaded by the runtime
47
+ (several flat files there — `build.md`, `typecheck.md`, `dev.md`, `signal.md`,
48
+ `cloudflare.md`, the `rag-*.md` set — exist as canon but never trigger as skills).
49
+
50
+ The YAML frontmatter is **load-bearing, not decoration**: `name` and
51
+ `description` are what the runtime matches against to decide whether to surface
52
+ the skill. A SKILL.md with no frontmatter never triggers. Put the trigger phrases
53
+ in `description` — the `## When to use` body section is read only *after* the
54
+ skill has already been selected.
55
+
45
56
  Use this template:
46
57
 
47
58
  ```markdown
59
+ ---
60
+ name: <slug>
61
+ description: <what this does, then the trigger conditions — "Use when …". Include the literal phrases a user would type. This field is the whole triggering surface.>
62
+ ---
63
+
48
64
  # <title> skill
49
65
 
50
66
  <one-sentence description — what this skill does for the model>
@@ -65,14 +81,31 @@ Use this template:
65
81
 
66
82
  **Step 4 — Wire it (if applicable)**
67
83
 
68
- - If the skill has a natural trigger phrase, append a row to the skills table in
69
- `.claude/CLAUDE.md` so it auto-loads.
84
+ - Auto-loading comes from the frontmatter `description`, not from any index
85
+ get the trigger phrases into that field or the skill stays dark.
86
+ - Then add the name to the `skills/` line in `.claude/CLAUDE.md` § Structure so
87
+ the harness inventory stays true. That listing is documentation of what exists;
88
+ it does not itself wire anything.
70
89
  - If it extends an existing skill, note the relation.
71
90
 
72
91
  **Step 5 — Close**
73
92
 
74
- Emit `signal("learning:harden", 1, "skill=<slug>")` and append one line to
75
- `text/learnings.md`:
93
+ Append one line to `text/learnings.md`. That line **is** the close — it is
94
+ deterministic and it is what the next cycle reads.
95
+
96
+ Do **not** emit `learning:harden` or `learning:know`. Neither is a registered
97
+ receiver: `grep -c '"learning:' packages/sdk/src/receivers.ts` → **0**. The
98
+ earlier version of this step instructed `signal("learning:know", { skill })`,
99
+ which fails silently — the same defect its own warning described, one line
100
+ down. The whole `learning:` namespace is unregistered; `harden`'s only shipped
101
+ wire is `chat:harden`, which needs a threadable `entityId` and does not fit a
102
+ skill close.
103
+
104
+ If you want the creation recorded in the substrate, `skill:save` is real
105
+ (`packages/sdk/src/receivers.ts`). Check the receiver exists before emitting —
106
+ the signature is `signal(receiver, data)`, and there is no three-argument form.
107
+
108
+ The line:
76
109
 
77
110
  ```
78
111
  - YYYY-MM-DD · skill:<slug> · crystallised from <source-slug> · source=skill-create
package/commands/sync.md CHANGED
@@ -14,10 +14,10 @@ Reconcile substrate state — report the growth loops, fire the on-demand ones,
14
14
  | L3 fade | channels cron `fade-tick` daily, rate 0.05 — TypeDB + D1 `claw_paths` | LIVE | `POST /api/fade` (web) |
15
15
  | L4 pay | signal with payment data → path revenue | LIVE | `POST /api/signal/<receiver>` |
16
16
  | L5 evolve | channels cron `evolution-tick` hourly → `agents:evolve` signal | LIVE | `POST /api/signal/agents:evolve` |
17
- | L6 know | channels cron `harden-tick` hourly (D1 strength≥10 → TypeDB hypotheses) | LIVE | `POST /api/ask/learning:know` |
17
+ | L6 know | channels cron `harden-tick` hourly (D1 strength≥10 → TypeDB hypotheses, via `rememberHypothesis`) | LIVE (cron only) | **no HTTP door** — `learning:know` is unregistered |
18
18
  | L7 frontier | read surface only — no detection job exists | READ-ONLY | `GET /api/frontiers` |
19
19
 
20
- **Not built (do not invoke, do not describe as live):** `GET /api/tick`, `POST /api/tasks/sync`, `src/engine/{doc-scan,task-parse,reusable-tasks}.ts`. The `sync-todo-docs.sh` hook still best-effort-POSTs `/api/tasks/sync` and silently no-ops — known drift. If a tick aggregator is ever wanted, it's a `/do` cycle (thin web route composing `fade()` + `agents:evolve` + `learning:know` + frontiers read), not a doc edit.
20
+ **Not built (do not invoke, do not describe as live):** `GET /api/tick`, `POST /api/tasks/sync`, `src/engine/{doc-scan,task-parse,reusable-tasks}.ts`. The `sync-todo-docs.sh` hook still best-effort-POSTs `/api/tasks/sync` and silently no-ops — known drift. If a tick aggregator is ever wanted, it's a `/do` cycle (thin web route composing `fade()` + `agents:evolve` + a harden receiver that must first be BUILT + frontiers read), not a doc edit.
21
21
 
22
22
  ## Nouns
23
23
 
@@ -28,19 +28,19 @@ Reconcile substrate state — report the growth loops, fire the on-demand ones,
28
28
  | `agents` | Scan agent `.md` frontmatter (`channels/src/lib/agent-md.ts` / `web/src/lib/agent-md.ts`) → sync units + skills + subscriptions to TypeDB | L1 |
29
29
  | `fade` | Fire L3 once — asymmetric decay | L3 |
30
30
  | `evolve` | Fire L5 once — rewrite struggling agents | L5 |
31
- | `know` | Fire L6 once — harden highways + hypothesize | L6 |
31
+ | `know` | **Read** L6 — no on-demand door; `harden-tick` is the only writer | L6 |
32
32
  | `frontier` | Read L7 — current frontiers (detection job unbuilt) | L7 |
33
33
  | `pay <receiver> <amt>` | Emit L4 payment signal | L4 |
34
- | `<path>` | Absorb a markdown file/dir — extract concepts `learning:know` | L6 |
34
+ | `<path>` | Absorb a markdown file/dir — extract concepts (no harden door; see below) | L6 |
35
35
 
36
36
  ## Steps
37
37
 
38
38
  ### *(default)*
39
39
 
40
- 1. `bun run verify` — W0 gate (skip if already passed this session)
40
+ 1. `(cd one.ie/web && bun run verify)` — W0 gate (skip if already passed this session). The `cd` is required: there is no root `package.json`, so a bare `bun run verify` from the repo root errors with "Script not found".
41
41
  2. `python3 .claude/scripts/do-rank.py` — rank + report the task queue
42
42
  3. Fire on-demand loops against the local dev server (or `ONE_API_URL`):
43
- `POST /api/fade` · `POST /api/ask/learning:know` · `GET /api/frontiers`
43
+ `POST /api/fade` · `GET /api/frontiers` L6 has no on-demand door (below)
44
44
  4. Report:
45
45
  ```
46
46
  Queue: N ready M gated K faded (top slug + score)
@@ -70,14 +70,24 @@ Reconcile substrate state — report the growth loops, fire the on-demand ones,
70
70
 
71
71
  ### evolve
72
72
 
73
- 1. `POST /api/signal/agents:evolve` same signal the hourly channels cron emits
74
- 2. Targets units with `success-rate < 0.50` AND `sample-count 20`
73
+ 1. **Select the targets first the receiver does not.** The hourly
74
+ `evolution-tick` (`channels/src/cron.ts`) runs the TypeDB query
75
+ `match $a isa actor, has aid $id, has success-rate $r, has sample-count $n; $r < 0.5; $n >= 20; select $id;`
76
+ and then posts **one signal per uid**. A bare `POST /api/signal/agents:evolve`
77
+ with an empty body targets nobody — it just writes a signal row.
78
+ 2. For each selected uid: `POST /api/signal/agents:evolve` with
79
+ `{ "data": { "uid": "<aid>" } }` (the cron posts to `$ONE_EVENTS_URL`; locally that is `http://localhost:4321`).
75
80
  3. Report: agents evaluated, agents evolved, generation numbers.
76
81
 
77
82
  ### know
78
83
 
79
- 1. `POST /api/ask/learning:know` promote strong paths to TypeDB hypotheses
80
- 2. Report: highways hardened, hypotheses written. (The hourly `harden-tick` cron does this automatically from D1 `claw_paths`.)
84
+ 1. **There is no manual door.** `learning:know` is in no registry, so
85
+ `POST /api/ask/learning:know` 404s this subcommand cannot force a harden.
86
+ The promotion happens only on the hourly `harden-tick` cron
87
+ (`channels/src/cron.ts:121`), which reads D1 `claw_paths` where
88
+ `strength >= 10` and calls `rememberHypothesis` directly.
89
+ 2. Report what the cron last wrote: highways hardened, hypotheses written. To
90
+ verify, read the hypotheses rather than trying to trigger a write.
81
91
 
82
92
  ### frontier
83
93
 
@@ -94,7 +104,7 @@ Reconcile substrate state — report the growth loops, fire the on-demand ones,
94
104
 
95
105
  1. Read markdown file or directory at `<path>` from `$ARGUMENTS`
96
106
  2. If directory: scan all `*.md` files recursively
97
- 3. Extract concepts → `POST /api/ask/learning:know` per concept (or agent specs → the `agents` flow)
107
+ 3. Extract concepts → **no door exists** (`learning:know` unregistered); record them in `text/` and let `harden-tick` promote what earns strength (or agent specs → the `agents` flow)
98
108
  4. Report: files processed, entities written.
99
109
 
100
110
  ---
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env bash
2
+ # AUTO-CONTINUE — Stop hook: keep the session moving without the operator
3
+ # typing "continue" / "do it" / "yes" / "merge and deploy" over and over.
4
+ #
5
+ # OPT-IN. Armed only while the flag file exists:
6
+ # .claude/auto-continue.local (toggle with /go on · /go off)
7
+ #
8
+ # Flag file format (all lines optional):
9
+ # max=12 — continuation budget per session (default 12)
10
+ # mission=<free text> — shown in every continuation directive
11
+ #
12
+ # When armed and the budget isn't spent, this hook BLOCKS the stop and hands
13
+ # Claude the standing instruction: finish in-flight work → merge and deploy
14
+ # when green → pick the next slug from todo.md → fan out when file-disjoint.
15
+ # Claude escapes the loop by finishing everything or removing the flag file
16
+ # (which it is told to do when genuinely blocked on a human-only decision).
17
+ #
18
+ # Safety:
19
+ # - per-session counter in /tmp caps continuations (no infinite loop)
20
+ # - absent flag file = hook is a no-op (default state)
21
+ # - ECC_DISABLED_HOOKS=hook:auto-continue disables it entirely
22
+ #
23
+ # Per Rule 1 (closed loop) — emits hook:auto-continue:{block,done}.
24
+
25
+ # shellcheck source=lib/hook.sh
26
+ source "$CLAUDE_PROJECT_DIR/.claude/hooks/lib/hook.sh"
27
+ # shellcheck source=lib/signal.sh
28
+ source "$CLAUDE_PROJECT_DIR/.claude/hooks/lib/signal.sh"
29
+ is_hook_disabled "hook:auto-continue" && exit 0
30
+
31
+ FLAG="$CLAUDE_PROJECT_DIR/.claude/auto-continue.local"
32
+ [[ -f "$FLAG" ]] || exit 0
33
+
34
+ PAYLOAD="${1:-}"
35
+
36
+ MAX=$(grep -E '^max=' "$FLAG" 2>/dev/null | head -1 | cut -d= -f2 | tr -dc '0-9')
37
+ [[ -z "$MAX" ]] && MAX=12
38
+ MISSION=$(grep -E '^mission=' "$FLAG" 2>/dev/null | head -1 | cut -d= -f2-)
39
+
40
+ SESSION_KEY=$(hook_session_key "$PAYLOAD")
41
+ COUNT_FILE="/tmp/oneie-auto-continue-${SESSION_KEY}.count"
42
+ COUNT=$(cat "$COUNT_FILE" 2>/dev/null | tr -dc '0-9')
43
+ [[ -z "$COUNT" ]] && COUNT=0
44
+ COUNT=$((COUNT + 1))
45
+
46
+ if (( COUNT > MAX )); then
47
+ # Budget spent — let the stop through, but say so out loud.
48
+ echo "[auto-continue] budget spent (${MAX} continuations this session) — letting the stop through. /go on resets next session; rm $COUNT_FILE resets now."
49
+ emit_signal "hook:auto-continue:done" 1 "count=$COUNT max=$MAX"
50
+ exit 0
51
+ fi
52
+ printf '%s' "$COUNT" > "$COUNT_FILE"
53
+
54
+ REASON="AUTO-CONTINUE is ON (/go). Standing instruction from the operator: fill the gaps · do it · continue · merge and deploy · fan out.
55
+
56
+ Do not stop yet — take the next action, in this order:
57
+ 1. Work in flight → finish it. A failed command is not a stopping point: diagnose, fix, retry.
58
+ 2. Work done and green (tsc + tests + kill-switch) → close the loop: commit by explicit path (check the current branch first), merge, deploy, verify live.
59
+ 3. Idle → read todo.md, take the top unblocked slug, run /do <slug>. Independent file-disjoint work → fan out parallel agents in one message.
60
+ 4. ONLY stop if genuinely blocked on a human-only decision (destructive action, spend, scope change) or everything is shipped and verified. In that case run: rm .claude/auto-continue.local — then report state honestly and stop.
61
+
62
+ Never fabricate green: if something fails, say so and keep working on it.${MISSION:+
63
+
64
+ Mission: $MISSION}
65
+
66
+ [continuation $COUNT of $MAX this session]"
67
+
68
+ emit_signal "hook:auto-continue:block" 1 "count=$COUNT max=$MAX"
69
+ jq -nc --arg r "$REASON" '{"decision":"block","reason":$r}'
70
+ exit 0
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env bash
2
+ # BRANCH-PIN — PreToolUse(Bash): the SHARED MAIN tree's HEAD is pinned.
3
+ #
4
+ # Multiple windows share ONE working tree. When any session switches HEAD
5
+ # (`git checkout <branch>`, `git switch`, `checkout -b`), every neighbouring
6
+ # session is silently pulled onto that branch — their reads see its files and
7
+ # their commits land on it (3 collisions 2026-07-08; do loops confused across
8
+ # sessions 2026-07-21). Branch work belongs in a linked worktree:
9
+ # bash .claude/scripts/do-auto.sh <slug> --setup-only # /do plans
10
+ # git worktree add -b feat/<slug> .do-worktrees/<slug> main # anything else
11
+ #
12
+ # Rule: on the shared main tree, any command that moves HEAD is denied —
13
+ # EXCEPT converging back to `main` (re-parking is the one allowed direction).
14
+ # Inside a linked worktree (git-dir under .git/worktrees/…) everything is
15
+ # allowed. Pathspec restores (`checkout [<ref>] -- <paths>`) don't move HEAD
16
+ # and pass through here (git-add-guard territory).
17
+ #
18
+ # Disable: ECC_DISABLED_HOOKS=hook:branch-pin
19
+
20
+ # shellcheck source=lib/hook.sh
21
+ source "$CLAUDE_PROJECT_DIR/.claude/hooks/lib/hook.sh"
22
+ is_hook_disabled "hook:branch-pin" && exit 0
23
+
24
+ PAYLOAD="${1:-}"
25
+ [[ -z "$PAYLOAD" ]] && exit 0
26
+
27
+ TOOL=$(printf '%s' "$PAYLOAD" | jq -r '.tool_name // empty' 2>/dev/null)
28
+ [[ "$TOOL" == "Bash" ]] || exit 0
29
+
30
+ CMD=$(printf '%s' "$PAYLOAD" | jq -r '.tool_input.command // empty' 2>/dev/null)
31
+ [[ -z "$CMD" ]] && exit 0
32
+
33
+ # The checkout/switch segment (up to a pipe/;/&&). `git worktree add` contains
34
+ # neither verb and never matches.
35
+ SEG=$(printf '%s' "$CMD" | grep -oE '\bgit\b[^|&;]*\b(checkout|switch)\b[^|&;]*' | head -1)
36
+ [[ -z "$SEG" ]] && exit 0
37
+
38
+ # A `--` pathspec means file restore, not a HEAD move.
39
+ printf '%s' "$SEG" | grep -qE '[[:space:]]--([[:space:]]|$)' && exit 0
40
+
41
+ # BSD sed has no \b — use an explicit space boundary.
42
+ ARGS=$(printf '%s' "$SEG" | sed -E 's/.*[[:space:]](checkout|switch)([[:space:]]+|$)/ /')
43
+
44
+ # Branch creation / detach / previous-branch shorthand always move HEAD.
45
+ if printf '%s' "$ARGS" | grep -qE '(^|[[:space:]])(-b|-B|-c|-C|--orphan|--detach|-)([[:space:]]|$)'; then
46
+ :
47
+ else
48
+ # First non-flag arg is the target ref; bare `git checkout` errors on its own.
49
+ REF=""
50
+ for a in $ARGS; do case "$a" in -*) ;; *) REF="$a"; break ;; esac; done
51
+ [[ -z "$REF" ]] && exit 0
52
+ [[ "$REF" == "main" ]] && exit 0 # converging home is allowed
53
+ fi
54
+
55
+ # Resolve the target dir: `git -C <path>`, else a leading `cd <path>`, else cwd.
56
+ _target() {
57
+ local c="$1" t=""
58
+ t=$(printf '%s' "$c" | grep -oE "git[[:space:]]+-C[[:space:]]+(\"[^\"]+\"|'[^']+'|[^[:space:]]+)" | head -1 | sed -E "s/^git[[:space:]]+-C[[:space:]]+//; s/^[\"']//; s/[\"']$//")
59
+ if [[ -z "$t" ]]; then
60
+ t=$(printf '%s' "$c" | grep -oE "(^|&&|;|\|)[[:space:]]*cd[[:space:]]+(\"[^\"]+\"|'[^']+'|[^[:space:]]+)" | head -1 | sed -E "s/.*cd[[:space:]]+//; s/^[\"']//; s/[\"']$//")
61
+ fi
62
+ [[ -z "$t" ]] && t=$(printf '%s' "$PAYLOAD" | jq -r '.cwd // empty' 2>/dev/null)
63
+ [[ -z "$t" ]] && t="."
64
+ printf '%s' "$t"
65
+ }
66
+ TARGET="$(_target "$CMD")"
67
+ case "$TARGET" in *'$'*) TARGET=$(printf '%s' "$PAYLOAD" | jq -r '.cwd // "."' 2>/dev/null) ;; esac
68
+
69
+ GITDIR=$(git -C "$TARGET" rev-parse --absolute-git-dir 2>/dev/null)
70
+ [[ -z "$GITDIR" ]] && exit 0 # not a git repo
71
+ case "$GITDIR" in */worktrees/*) exit 0 ;; esac # linked worktree — switch freely
72
+
73
+ MSG="[branch-pin] HEAD switches on the shared main tree are blocked.
74
+
75
+ Multiple sessions share this working tree; moving HEAD pulls every one of
76
+ them onto your branch — their reads and commits land there silently.
77
+
78
+ Do the work in a linked worktree instead:
79
+ - /do plan: bash .claude/scripts/do-auto.sh <slug> --setup-only
80
+ - anything else: git worktree add -b feat/<slug> .do-worktrees/<slug> main
81
+ - returning home: git switch main (always allowed)
82
+
83
+ Override for a deliberate switch: ECC_DISABLED_HOOKS=hook:branch-pin"
84
+ jq -nc --arg r "$MSG" '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":$r}}'
85
+ exit 0
@@ -34,9 +34,18 @@ printf '%s' "$CMD" | grep -qE '\bgit\b' || exit 0
34
34
  # Blanket stage = `add -A`, `add --all`, `add .` (bare dot), or `commit` with a
35
35
  # short-flag cluster containing `a` (-a/-am/…) or `--all`. (`--amend`/`--author`
36
36
  # are `--` long flags, so the `-[a-z]*a` short-cluster test never matches them.)
37
+ # Also blanket: any MUTATING `git stash` (bare/push/-u/pop/apply/drop) — a stash
38
+ # on the shared main tree sweeps every neighbour's uncommitted work into one
39
+ # stash entry, and pop/apply dumps foreign state back mixed with yours
40
+ # (near-miss 2026-07-06: a loop conductor ran `git stash -u` on main and picked
41
+ # up a neighbour's edits). `stash list` / `stash show` are read-only — allowed.
37
42
  _is_blanket() {
38
43
  printf '%s' "$1" | grep -qE '\bgit\b[^|&;]*\badd\b[^|&;]*(-A\b|--all\b|[[:space:]]\.([[:space:]]|$))' && return 0
39
44
  printf '%s' "$1" | grep -qE '\bgit\b[^|&;]*\bcommit\b[^|&;]*([[:space:]]-[a-zA-Z]*a[a-zA-Z]*\b|--all\b)' && return 0
45
+ if printf '%s' "$1" | grep -qE '\bgit\b[^|&;]*\bstash\b' \
46
+ && ! printf '%s' "$1" | grep -qE '\bgit\b[^|&;]*\bstash\b[[:space:]]+(list|show)\b'; then
47
+ return 0
48
+ fi
40
49
  return 1
41
50
  }
42
51
  _is_blanket "$CMD" || exit 0
@@ -64,17 +73,19 @@ GITDIR=$(git -C "$TARGET" rev-parse --absolute-git-dir 2>/dev/null)
64
73
  case "$GITDIR" in */worktrees/*) exit 0 ;; esac # isolated linked worktree — blanket is safe
65
74
 
66
75
  # Main tree → deny.
67
- MSG="[git-add-guard] Blanket staging on the shared main tree is blocked.
76
+ MSG="[git-add-guard] Blanket staging/stashing on the shared main tree is blocked.
68
77
 
69
- Multiple windows share this working tree. A blanket add (-A, bare dot, or commit -a)
70
- would sweep a neighbouring window uncommitted work into your commit
71
- (the do(funnels) tangle, 2026-06-20).
78
+ Multiple windows share this working tree. A blanket add (-A, bare dot, commit -a)
79
+ or a mutating stash (bare/push/-u/pop/apply) sweeps a neighbouring window's
80
+ uncommitted work into your commit or stash
81
+ (the do(funnels) tangle 2026-06-20; the stash -u near-miss 2026-07-06).
72
82
 
73
83
  Do one of:
74
84
  - stage by explicit path: git add path/to/file ...
75
85
  - isolate the work: git worktree add -b feat/<slug> ../wt-<slug> main
86
+ - read-only stash views (git stash list / show) are always allowed
76
87
 
77
88
  Deploy/release (a command containing git push) is exempt.
78
- Override once for this command: ECC_DISABLED_HOOKS=hook:git-add-guard"
89
+ Override once for a deliberate scoped action: ECC_DISABLED_HOOKS=hook:git-add-guard"
79
90
  jq -nc --arg r "$MSG" '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":$r}}'
80
91
  exit 0
@@ -16,6 +16,22 @@ if [[ -z "$FILE" ]] || [[ ! "$FILE" =~ \.(ts|tsx|js|jsx)$ ]]; then
16
16
  exit 0
17
17
  fi
18
18
 
19
+ # Dynamic workflow scripts fail SILENTLY — a syntax error doesn't error, it stops
20
+ # the workflow from launching at all. biome won't catch the two structural traps
21
+ # (a second top-level export; a missing `meta` block), and `node --check` exits 0
22
+ # for any file starting with `export`. wf-check parses the body as the runtime
23
+ # does. Non-blocking, per this hook's contract — but loud, because the default
24
+ # failure mode is silence.
25
+ if [[ "$FILE" == *".claude/workflows/"*.js ]]; then
26
+ if ! WF=$(cd "$CLAUDE_PROJECT_DIR" && node .claude/scripts/wf-check.mjs "$FILE" 2>&1); then
27
+ echo "wf-check: $(echo "$WF" | grep FAIL || echo "$WF")" >&2
28
+ echo "wf-check: this workflow will NOT launch until fixed" >&2
29
+ emit_signal "hook:post-edit:warn" -1 "file=$(basename "$FILE") wf-check=fail"
30
+ exit 0
31
+ fi
32
+ emit_signal "hook:post-edit:ok" 1 "file=$(basename "$FILE") wf-check=ok"
33
+ fi
34
+
19
35
  # Quick biome lint on the single file (non-blocking)
20
36
  RESULT=$(cd "$CLAUDE_PROJECT_DIR" && bun biome check "$FILE" 2>&1)
21
37
  EXIT=$?
@@ -39,15 +39,20 @@ MODULES=(
39
39
  "sync"
40
40
  "backup"
41
41
  )
42
+ # `/name` = a registered directory skill, invocable via the Skill tool.
43
+ # `name.md` = a flat file under .claude/skills/ — canon, but NOT registered in
44
+ # this tree, so it cannot be invoked by name. Read it by path. (The published
45
+ # oneie-claude plugin registers these, because sync-claude-mirror.sh converts
46
+ # each flat file into <name>/SKILL.md on the way out.)
42
47
  HINTS=(
43
- "/astro · /react19 · /shadcn · /dev · /build"
44
- "/cloudflare · /ai-sdk · /signal"
45
- "/cloudflare · /typedb · /signal"
46
- "/typecheck · /signal (substrate verbs)"
47
- "/typecheck · MCP server"
48
- "/typecheck · CLI bins"
49
- "/cloudflare (Scheduled Worker)"
50
- "/cloudflare (Scheduled Worker)"
48
+ "/astro · /react19 · /shadcn · dev.md · build.md"
49
+ "cloudflare.md · /ai-sdk · signal.md"
50
+ "cloudflare.md · /typedb · signal.md"
51
+ "typecheck.md · signal.md (substrate verbs)"
52
+ "typecheck.md · MCP server"
53
+ "typecheck.md · CLI bins"
54
+ "cloudflare.md (Scheduled Worker)"
55
+ "cloudflare.md (Scheduled Worker)"
51
56
  )
52
57
 
53
58
  NEWEST_TS=0
@@ -25,6 +25,11 @@ if [ -n "$1" ]; then
25
25
  esac
26
26
  fi
27
27
 
28
+ # Hook-driven run: this fires on every session open and every plan edit, so the ranker's
29
+ # tasks:everywhere board read gets a short budget and degrades to file-only rather than
30
+ # blocking the session on an ~11s receiver. An explicit `/do next` waits for the real answer.
31
+ export DO_RANK_HOOK=1
32
+
28
33
  # Close → weight: reconcile path strength from learnings.md closes (idempotent) before
29
34
  # we rank, so a cycle close moves the next pick autonomously. See text/loop-plan.md.
30
35
  python3 "$CLAUDE_PROJECT_DIR/.claude/scripts/do-rank.py" --sync-closes >/dev/null 2>&1 || true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oneie/claude",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "ONE Claude Code plugin — /do lifecycle, W0-W4 BUILD engine, 7-canon reconcile, ONE substrate via MCP, signals, and rules",
5
5
  "files": [
6
6
  ".claude-plugin",
package/rules/api.md CHANGED
@@ -45,6 +45,15 @@ The `>` separator works as a fallback to `→`. Always pass `{ strength }` in th
45
45
 
46
46
  Active state (saved, archived, completed) belongs on the pheromone path, not in `localStorage`. Poll `/api/export/highways?from=source&limit=200` and classify by strength/resistance thresholds. This keeps state honest across devices.
47
47
 
48
+ ## Authorize off the context, never the body
49
+
50
+ Scope every read and write to `ctx.ownerSlug`. A `slug`, `actorId`, `gid`, or
51
+ `workspace` arriving in the request body or query string is **caller-supplied
52
+ input, not identity** — trusting one is an IDOR, and this family has had ~80 of
53
+ them fixed. A `?slug=` route must call `authorizeWorkspace` before it touches
54
+ data. Ownership questions resolve by the authority walk (`schema/roles.tql`),
55
+ not by comparing a body field to anything.
56
+
48
57
  ## No stubs
49
58
 
50
59
  Do not create a no-op endpoint (one that always returns `[]` or `{ok:true}`) as a placeholder. If the backend isn't ready, the caller handles the empty response from `signal`/`ask`.
package/rules/design.md CHANGED
@@ -203,11 +203,21 @@ Three layers, all automatic:
203
203
  2. **PostToolUse hook** — `.claude/hooks/design-check.sh` greps every Write/Edit
204
204
  to `one.ie/web/**/*.{tsx,astro,css}` for banned patterns. Exit 2 on violation feeds
205
205
  the diff back to Claude as a tool error; the model self-corrects next turn.
206
- 3. **This rule** — auto-loaded on the same files via `.claude/settings.json`,
207
- so the constraints are in context before the first character is written.
206
+ 3. **This rule** — auto-loaded on the same files via the `paths:` frontmatter at
207
+ the top of this file (not `settings.json`, which wires hooks only), so the
208
+ constraints are in context before the first character is written.
208
209
 
209
210
  The hook allowlists `Layout.astro` (token source) and `design.astro` (showcase).
210
- There is no opt-out for other files.
211
+
212
+ **Layers 2 and 3 are edit-triggered, so pre-existing violations survive.** The
213
+ hook is PostToolUse: it only sees a file when that file is written. Nothing
214
+ sweeps the tree, and layer 1 structurally cannot catch a hex string inside a JS
215
+ object — it nulls Tailwind palette *classes*, not literals. So a file untouched
216
+ since this rule landed can carry banned patterns indefinitely.
217
+ `src/components/paths/PathGraph.tsx` did: it carried hex literals at lines 27,
218
+ 28, 29 and 55 until they were swept to `var(--color-{success,secondary,destructive})`.
219
+ Treat "the hook is green" as "nobody has edited the offender", not as "the tree
220
+ is clean".
211
221
 
212
222
  ---
213
223