@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.
- package/agents/w1-recon.md +9 -4
- package/agents/w2-decide.md +51 -28
- package/agents/w3-edit.md +70 -78
- package/agents/w4-verify.md +164 -69
- package/commands/browser.md +98 -35
- package/commands/cc-connect.md +6 -0
- package/commands/chat.md +13 -1
- package/commands/close.md +45 -19
- package/commands/create.md +20 -10
- package/commands/db-sync.md +5 -1
- package/commands/deploy.md +174 -87
- package/commands/do-autonomous.md +31 -20
- package/commands/do-improve.md +4 -4
- package/commands/do-show.md +4 -3
- package/commands/do.md +53 -13
- package/commands/go.md +75 -0
- package/commands/improve.md +4 -2
- package/commands/kill.md +6 -8
- package/commands/notify.md +15 -2
- package/commands/oo-push.md +24 -9
- package/commands/rag.md +6 -0
- package/commands/release.md +46 -25
- package/commands/restart.md +5 -4
- package/commands/see.md +45 -35
- package/commands/skill-create.md +38 -5
- package/commands/sync.md +21 -11
- package/hooks/scripts/auto-continue.sh +70 -0
- package/hooks/scripts/branch-pin.sh +85 -0
- package/hooks/scripts/git-add-guard.sh +16 -5
- package/hooks/scripts/post-edit-check.sh +16 -0
- package/hooks/scripts/session-start.sh +13 -8
- package/hooks/scripts/sync-priority-todo.sh +5 -0
- package/package.json +1 -1
- package/rules/api.md +9 -0
- package/rules/design.md +13 -3
- package/rules/documentation.md +30 -71
- package/rules/engine.md +8 -1
- package/rules/ui.md +5 -1
- package/scripts/__pycache__/do-rank.cpython-313.pyc +0 -0
- package/scripts/browser-check.mjs +44 -103
- package/scripts/cc-events-proof.sh +13 -12
- package/scripts/chrome.mjs +381 -0
- package/scripts/do-analyze.sh +109 -4
- package/scripts/do-auto.sh +350 -43
- package/scripts/do-consumer-sweep.sh +72 -0
- package/scripts/do-derives-check.sh +88 -0
- package/scripts/do-fleet.sh +50 -1
- package/scripts/do-killswitch-audit.py +33 -14
- package/scripts/do-promise-lint.sh +150 -4
- package/scripts/do-promise-settle.sh +131 -9
- package/scripts/do-prove.sh +197 -17
- package/scripts/do-rank.py +606 -20
- package/scripts/do-rubric.py +21 -2
- package/scripts/do-signal.sh +157 -17
- package/scripts/do-smoke.sh +9 -0
- package/scripts/do-substrate-check.sh +49 -0
- package/scripts/do-tasks-wire-check.sh +81 -0
- package/scripts/do-tier.sh +90 -5
- package/scripts/do-ui-gate.sh +332 -0
- package/scripts/do-untracked-gate.sh +231 -0
- package/scripts/do-walk.sh +344 -0
- package/scripts/factory-check.sh +747 -0
- package/scripts/factory-repo.sh +1361 -0
- package/scripts/factory-tasks-check.sh +85 -0
- package/scripts/outcome-pull.ts +279 -0
- package/scripts/promise-manifest.mjs +167 -0
- package/scripts/reconcile-allow.txt +5 -0
- package/scripts/rubric-weights.json +64 -0
- package/scripts/spine-canary.sh +20 -0
- package/scripts/typedb-cluster-status.sh +128 -0
- package/scripts/typedb-env.sh +182 -0
- package/scripts/typedb-flap-recorder.sh +85 -0
- package/scripts/typedb-probes/containment-probe.py +88 -0
- package/scripts/typedb-probes/panic-probe-version.py +92 -0
- package/scripts/typedb-probes/panic-probe.py +77 -0
- package/scripts/typedb-scratch.sh +73 -0
- package/scripts/urls-lint.sh +58 -0
- package/scripts/w4-rubric.ts +96 -12
- package/scripts/wf-check.mjs +75 -0
- package/skills/ai-ui/SKILL.md +1 -1
- package/skills/astro/SKILL.md +177 -132
- package/skills/astro/add-content-collection.md +29 -13
- package/skills/astro/check-build.md +19 -13
- package/skills/astro/create-component.md +36 -9
- package/skills/astro/create-page.md +39 -10
- package/skills/astro/optimize-performance.md +36 -8
- package/skills/cli/SKILL.md +254 -220
- package/skills/dev/SKILL.md +1 -1
- package/skills/directory-autofill/SKILL.md +68 -0
- package/skills/docs/SKILL.md +4 -4
- package/skills/mcp/SKILL.md +186 -156
- package/skills/promise-make/SKILL.md +2 -2
- package/skills/puck/SKILL.md +465 -250
- package/skills/react19/SKILL.md +196 -296
- package/skills/reactflow/SKILL.md +387 -412
- package/skills/sdk/SKILL.md +167 -106
- package/skills/shadcn/SKILL.md +245 -201
- package/skills/signal/SKILL.md +5 -0
- package/skills/sui/SKILL.md +6 -1
- package/skills/tutorial/SKILL.md +15 -0
- package/skills/typedb/SKILL.md +427 -217
- package/skills/typedb/examples/python-patterns.py +11 -4
- package/skills/typedb/examples/query-patterns.tql +8 -3
- package/skills/typedb/examples/schema-patterns.tql +4 -2
- package/skills/typedb/reference/migration-2x-3x.md +19 -1
- package/skills/typedb/reference/python-driver.md +17 -1
- package/skills/voice/SKILL.md +117 -0
- package/skills/writer/SKILL.md +29 -12
- package/templates/template-feature.md +26 -1
- package/templates/template-tests.md +4 -0
- 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>` |
|
|
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 |
|
|
30
|
-
| highways | `follow()` path read |
|
|
31
|
-
| toxic | `follow()` path read |
|
|
32
|
-
| frontiers | `follow()` gap read |
|
|
33
|
-
| paths | `follow()` path query |
|
|
34
|
-
| hypotheses | TypeDB read |
|
|
35
|
-
| evolved | TypeDB read | units
|
|
36
|
-
| revenue | TypeDB read |
|
|
37
|
-
| events | TypeDB read | signal history |
|
|
38
|
-
| 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.
|
|
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?
|
|
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/
|
|
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/
|
|
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/
|
|
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.
|
|
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.
|
|
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.
|
|
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/
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
- **
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
-
|
|
149
|
-
|
|
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
|
-
|
|
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.*
|
package/commands/skill-create.md
CHANGED
|
@@ -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
|
|
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
|
-
-
|
|
69
|
-
|
|
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
|
-
|
|
75
|
-
|
|
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 | `
|
|
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` +
|
|
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` |
|
|
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
|
|
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` · `
|
|
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.
|
|
74
|
-
|
|
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. `
|
|
80
|
-
|
|
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 → `
|
|
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,
|
|
70
|
-
|
|
71
|
-
|
|
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
|
|
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 ·
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
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
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
|
|
207
|
-
|
|
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
|
-
|
|
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
|
|